summaryrefslogtreecommitdiffstats
path: root/security/nss/lib/libpkix/pkix_pl_nss
diff options
context:
space:
mode:
authorMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
committerMatt A. Tobin <mattatobin@localhost.localdomain>2018-02-02 04:16:08 -0500
commit5f8de423f190bbb79a62f804151bc24824fa32d8 (patch)
tree10027f336435511475e392454359edea8e25895d /security/nss/lib/libpkix/pkix_pl_nss
parent49ee0794b5d912db1f95dce6eb52d781dc210db5 (diff)
downloadUXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.gz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.lz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.tar.xz
UXP-5f8de423f190bbb79a62f804151bc24824fa32d8.zip
Add m-esr52 at 52.6.0
Diffstat (limited to 'security/nss/lib/libpkix/pkix_pl_nss')
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/Makefile48
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/config.mk15
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/manifest.mn11
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/module/Makefile48
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/module/config.mk35
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/exports.gyp36
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/module/manifest.mn38
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/module.gyp41
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c699
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.h65
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.c1282
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.h34
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c1147
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.h62
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c1654
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.h139
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.c1116
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.h75
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.c2493
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.h82
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.c757
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.h86
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.c786
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.h96
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapt.h314
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaptemplates.c417
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.c319
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.h52
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c1039
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.h31
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c1695
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.h209
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/pki/Makefile49
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/pki/config.mk15
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/exports.gyp41
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/pki/manifest.mn53
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pki.gyp39
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.c407
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.h47
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c3714
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.h107
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.c371
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.h50
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.c386
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.h49
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.c365
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.h52
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.c1068
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.h48
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.c151
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.h53
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.c880
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.h46
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.c466
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.h55
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.c873
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.h49
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.c874
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.h49
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.c1274
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.h68
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.c251
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.h53
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.c441
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.h61
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.c1067
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.h106
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.c489
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.h38
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.c667
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.h74
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/Makefile49
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/config.mk15
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/system/exports.gyp37
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/manifest.mn46
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bigint.c398
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bigint.h40
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bytearray.c504
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bytearray.h40
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_common.c1073
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_common.h159
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_error.c26
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.c383
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.h29
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_lifecycle.c279
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_lifecycle.h91
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mem.c168
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mem.h24
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_monitorlock.c136
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_monitorlock.h33
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mutex.c163
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mutex.h33
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.c1440
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.h76
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_oid.c316
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_oid.h39
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_primhash.c584
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_primhash.h102
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_rwlock.c217
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_rwlock.h35
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.c621
-rwxr-xr-xsecurity/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.h37
-rw-r--r--security/nss/lib/libpkix/pkix_pl_nss/system/system.gyp36
103 files changed, 37096 insertions, 0 deletions
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/Makefile b/security/nss/lib/libpkix/pkix_pl_nss/Makefile
new file mode 100755
index 000000000..36524f56a
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/Makefile
@@ -0,0 +1,48 @@
+#! gmake
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#######################################################################
+# (1) Include initial platform-independent assignments (MANDATORY). #
+#######################################################################
+
+include manifest.mn
+
+#######################################################################
+# (2) Include "global" configuration information. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/config.mk
+
+#######################################################################
+# (3) Include "component" configuration information. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (4) Include "local" platform-dependent assignments (OPTIONAL). #
+#######################################################################
+
+include config.mk
+
+#######################################################################
+# (5) Execute "global" rules. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/rules.mk
+
+#######################################################################
+# (6) Execute "component" rules. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (7) Execute "local" rules. (OPTIONAL). #
+#######################################################################
+
+export:: private_export
+
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/config.mk b/security/nss/lib/libpkix/pkix_pl_nss/config.mk
new file mode 100755
index 000000000..b8c03de79
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/config.mk
@@ -0,0 +1,15 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#
+# Override TARGETS variable so that only static libraries
+# are specifed as dependencies within rules.mk.
+#
+
+TARGETS = $(LIBRARY)
+SHARED_LIBRARY =
+IMPORT_LIBRARY =
+PROGRAM =
+
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/manifest.mn b/security/nss/lib/libpkix/pkix_pl_nss/manifest.mn
new file mode 100755
index 000000000..f3c83511a
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/manifest.mn
@@ -0,0 +1,11 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+CORE_DEPTH = ../../..
+DEPTH = ../../..
+
+#
+DIRS = pki system module \
+ $(NULL)
+
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/Makefile b/security/nss/lib/libpkix/pkix_pl_nss/module/Makefile
new file mode 100755
index 000000000..36524f56a
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/Makefile
@@ -0,0 +1,48 @@
+#! gmake
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#######################################################################
+# (1) Include initial platform-independent assignments (MANDATORY). #
+#######################################################################
+
+include manifest.mn
+
+#######################################################################
+# (2) Include "global" configuration information. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/config.mk
+
+#######################################################################
+# (3) Include "component" configuration information. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (4) Include "local" platform-dependent assignments (OPTIONAL). #
+#######################################################################
+
+include config.mk
+
+#######################################################################
+# (5) Execute "global" rules. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/rules.mk
+
+#######################################################################
+# (6) Execute "component" rules. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (7) Execute "local" rules. (OPTIONAL). #
+#######################################################################
+
+export:: private_export
+
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/config.mk b/security/nss/lib/libpkix/pkix_pl_nss/module/config.mk
new file mode 100755
index 000000000..2926747a2
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/config.mk
@@ -0,0 +1,35 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#
+# Override TARGETS variable so that only static libraries
+# are specifed as dependencies within rules.mk.
+#
+
+TARGETS = $(LIBRARY)
+SHARED_LIBRARY =
+IMPORT_LIBRARY =
+PROGRAM =
+
+ifdef NSS_PKIX_NO_LDAP
+LDAP_HEADERS =
+LDAP_CSRCS =
+else
+LDAP_HEADERS = \
+ pkix_pl_ldapt.h \
+ pkix_pl_ldapcertstore.h \
+ pkix_pl_ldapresponse.h \
+ pkix_pl_ldaprequest.h \
+ pkix_pl_ldapdefaultclient.h \
+ $(NULL)
+
+LDAP_CSRCS = \
+ pkix_pl_ldaptemplates.c \
+ pkix_pl_ldapcertstore.c \
+ pkix_pl_ldapresponse.c \
+ pkix_pl_ldaprequest.c \
+ pkix_pl_ldapdefaultclient.c \
+ $(NULL)
+endif
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/exports.gyp b/security/nss/lib/libpkix/pkix_pl_nss/module/exports.gyp
new file mode 100644
index 000000000..064a17ce4
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/exports.gyp
@@ -0,0 +1,36 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+{
+ 'includes': [
+ '../../../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'lib_libpkix_pkix_pl_nss_module_exports',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'files': [
+ 'pkix_pl_aiamgr.h',
+ 'pkix_pl_colcertstore.h',
+ 'pkix_pl_httpcertstore.h',
+ 'pkix_pl_httpdefaultclient.h',
+ 'pkix_pl_ldapcertstore.h',
+ 'pkix_pl_ldapdefaultclient.h',
+ 'pkix_pl_ldaprequest.h',
+ 'pkix_pl_ldapresponse.h',
+ 'pkix_pl_ldapt.h',
+ 'pkix_pl_nsscontext.h',
+ 'pkix_pl_pk11certstore.h',
+ 'pkix_pl_socket.h'
+ ],
+ 'destination': '<(nss_private_dist_dir)/<(module)'
+ }
+ ]
+ }
+ ],
+ 'variables': {
+ 'module': 'nss'
+ }
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/manifest.mn b/security/nss/lib/libpkix/pkix_pl_nss/module/manifest.mn
new file mode 100755
index 000000000..63bfd707e
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/manifest.mn
@@ -0,0 +1,38 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+CORE_DEPTH = ../../../..
+
+EXPORTS = \
+ $(NULL)
+
+PRIVATE_EXPORTS = \
+ pkix_pl_aiamgr.h \
+ pkix_pl_colcertstore.h \
+ pkix_pl_httpcertstore.h \
+ pkix_pl_httpdefaultclient.h \
+ $(LDAP_HEADERS) \
+ pkix_pl_nsscontext.h \
+ pkix_pl_pk11certstore.h \
+ pkix_pl_socket.h \
+ $(NULL)
+
+MODULE = nss
+
+DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\" -DSHLIB_VERSION=\"$(LIBRARY_VERSION)\"
+
+
+CSRCS = \
+ pkix_pl_aiamgr.c \
+ pkix_pl_colcertstore.c \
+ pkix_pl_httpcertstore.c \
+ pkix_pl_httpdefaultclient.c \
+ $(LDAP_CSRCS) \
+ pkix_pl_nsscontext.c \
+ pkix_pl_pk11certstore.c \
+ pkix_pl_socket.c \
+ $(NULL)
+
+LIBRARY_NAME = pkixmodule
+
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/module.gyp b/security/nss/lib/libpkix/pkix_pl_nss/module/module.gyp
new file mode 100644
index 000000000..8d7459ded
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/module.gyp
@@ -0,0 +1,41 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+{
+ 'includes': [
+ '../../../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'pkixmodule',
+ 'type': 'static_library',
+ 'sources': [
+ 'pkix_pl_aiamgr.c',
+ 'pkix_pl_colcertstore.c',
+ 'pkix_pl_httpcertstore.c',
+ 'pkix_pl_httpdefaultclient.c',
+ 'pkix_pl_ldapcertstore.c',
+ 'pkix_pl_ldapdefaultclient.c',
+ 'pkix_pl_ldaprequest.c',
+ 'pkix_pl_ldapresponse.c',
+ 'pkix_pl_ldaptemplates.c',
+ 'pkix_pl_nsscontext.c',
+ 'pkix_pl_pk11certstore.c',
+ 'pkix_pl_socket.c'
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports'
+ ]
+ }
+ ],
+ 'target_defaults': {
+ 'defines': [
+ 'SHLIB_SUFFIX=\"<(dll_suffix)\"',
+ 'SHLIB_PREFIX=\"<(dll_prefix)\"',
+ 'SHLIB_VERSION=\"\"'
+ ]
+ },
+ 'variables': {
+ 'module': 'nss'
+ }
+} \ No newline at end of file
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c
new file mode 100644
index 000000000..d9f566230
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.c
@@ -0,0 +1,699 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_aiamgr.c
+ *
+ * AIAMgr Object Definitions
+ *
+ */
+
+#include "pkix_pl_aiamgr.h"
+extern PKIX_PL_HashTable *aiaConnectionCache;
+
+#ifndef NSS_PKIX_NO_LDAP
+/* --Virtual-LdapClient-Functions------------------------------------ */
+
+PKIX_Error *
+PKIX_PL_LdapClient_InitiateRequest(
+ PKIX_PL_LdapClient *client,
+ LDAPRequestParams *requestParams,
+ void **pNBIO,
+ PKIX_List **pResponse,
+ void *plContext)
+{
+ PKIX_ENTER(LDAPCLIENT, "PKIX_PL_LdapClient_InitiateRequest");
+ PKIX_NULLCHECK_TWO(client, client->initiateFcn);
+
+ PKIX_CHECK(client->initiateFcn
+ (client, requestParams, pNBIO, pResponse, plContext),
+ PKIX_LDAPCLIENTINITIATEREQUESTFAILED);
+cleanup:
+
+ PKIX_RETURN(LDAPCLIENT);
+
+}
+
+PKIX_Error *
+PKIX_PL_LdapClient_ResumeRequest(
+ PKIX_PL_LdapClient *client,
+ void **pNBIO,
+ PKIX_List **pResponse,
+ void *plContext)
+{
+ PKIX_ENTER(LDAPCLIENT, "PKIX_PL_LdapClient_ResumeRequest");
+ PKIX_NULLCHECK_TWO(client, client->resumeFcn);
+
+ PKIX_CHECK(client->resumeFcn
+ (client, pNBIO, pResponse, plContext),
+ PKIX_LDAPCLIENTRESUMEREQUESTFAILED);
+cleanup:
+
+ PKIX_RETURN(LDAPCLIENT);
+
+}
+#endif /* !NSS_PKIX_NO_LDAP */
+
+/* --Private-AIAMgr-Functions----------------------------------*/
+
+/*
+ * FUNCTION: pkix_pl_AIAMgr_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_pki.h)
+ */
+static PKIX_Error *
+pkix_pl_AIAMgr_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_AIAMgr *aiaMgr = NULL;
+
+ PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_AIAMGR_TYPE, plContext),
+ PKIX_OBJECTNOTAIAMGR);
+
+ aiaMgr = (PKIX_PL_AIAMgr *)object;
+
+ /* pointer to cert cache */
+ /* pointer to crl cache */
+ aiaMgr->method = 0;
+ aiaMgr->aiaIndex = 0;
+ aiaMgr->numAias = 0;
+ PKIX_DECREF(aiaMgr->aia);
+ PKIX_DECREF(aiaMgr->location);
+ PKIX_DECREF(aiaMgr->results);
+#ifndef NSS_PKIX_NO_LDAP
+ PKIX_DECREF(aiaMgr->client.ldapClient);
+#endif
+
+cleanup:
+
+ PKIX_RETURN(AIAMGR);
+}
+
+/*
+ * FUNCTION: pkix_pl_AIAMgr_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_AIAMGR_TYPE and its related functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_AIAMgr_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry *entry = &systemClasses[PKIX_AIAMGR_TYPE];
+
+ PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_RegisterSelf");
+
+ entry->description = "AIAMgr";
+ entry->typeObjectSize = sizeof(PKIX_PL_AIAMgr);
+ entry->destructor = pkix_pl_AIAMgr_Destroy;
+
+ PKIX_RETURN(AIAMGR);
+}
+
+#ifndef NSS_PKIX_NO_LDAP
+/*
+ * FUNCTION: pkix_pl_AiaMgr_FindLDAPClient
+ * DESCRIPTION:
+ *
+ * This function checks the collection of LDAPClient connections held by the
+ * AIAMgr pointed to by "aiaMgr" for one matching the domain name given by
+ * "domainName". The string may include a port number: e.g., "betty.nist.gov"
+ * or "nss.red.iplanet.com:1389". If a match is found, that LDAPClient is
+ * stored at "pClient". Otherwise, an LDAPClient is created and added to the
+ * collection, and then stored at "pClient".
+ *
+ * PARAMETERS:
+ * "aiaMgr"
+ * The AIAMgr whose LDAPClient connected are to be managed. Must be
+ * non-NULL.
+ * "domainName"
+ * Address of a string pointing to a server name. Must be non-NULL.
+ * An empty string (which means no <host> is given in the LDAP URL) is
+ * not supported.
+ * "pClient"
+ * Address at which the returned LDAPClient is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an AIAMgr Error if the function fails in a non-fatal way
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_AiaMgr_FindLDAPClient(
+ PKIX_PL_AIAMgr *aiaMgr,
+ char *domainName,
+ PKIX_PL_LdapClient **pClient,
+ void *plContext)
+{
+ PKIX_PL_String *domainString = NULL;
+ PKIX_PL_LdapDefaultClient *client = NULL;
+
+ PKIX_ENTER(AIAMGR, "pkix_pl_AiaMgr_FindLDAPClient");
+ PKIX_NULLCHECK_THREE(aiaMgr, domainName, pClient);
+
+ /*
+ * An LDAP URL may not have a <host> part, for example,
+ * ldap:///o=University%20of%20Michigan,c=US
+ * PKIX_PL_LdapDefaultClient doesn't know how to discover the default
+ * LDAP server, so we don't support this kind of LDAP URL.
+ */
+ if (*domainName == '\0') {
+ /* Simulate a PKIX_PL_LdapDefaultClient_CreateByName failure. */
+ PKIX_ERROR(PKIX_LDAPDEFAULTCLIENTCREATEBYNAMEFAILED);
+ }
+
+ /* create PKIX_PL_String from domain name */
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, domainName, 0, &domainString, plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ /* Is this domainName already in cache? */
+ PKIX_CHECK(PKIX_PL_HashTable_Lookup
+ (aiaConnectionCache,
+ (PKIX_PL_Object *)domainString,
+ (PKIX_PL_Object **)&client,
+ plContext),
+ PKIX_HASHTABLELOOKUPFAILED);
+
+ if (client == NULL) {
+
+ /* No, create a connection (and cache it) */
+ PKIX_CHECK(PKIX_PL_LdapDefaultClient_CreateByName
+ (domainName,
+ /* Do not use NBIO until we verify, that
+ * it is working. For now use 1 min timeout. */
+ PR_SecondsToInterval(
+ ((PKIX_PL_NssContext*)plContext)->timeoutSeconds),
+ NULL,
+ &client,
+ plContext),
+ PKIX_LDAPDEFAULTCLIENTCREATEBYNAMEFAILED);
+
+ PKIX_CHECK(PKIX_PL_HashTable_Add
+ (aiaConnectionCache,
+ (PKIX_PL_Object *)domainString,
+ (PKIX_PL_Object *)client,
+ plContext),
+ PKIX_HASHTABLEADDFAILED);
+
+ }
+
+ *pClient = (PKIX_PL_LdapClient *)client;
+
+cleanup:
+
+ PKIX_DECREF(domainString);
+
+ PKIX_RETURN(AIAMGR);
+}
+#endif /* !NSS_PKIX_NO_LDAP */
+
+PKIX_Error *
+pkix_pl_AIAMgr_GetHTTPCerts(
+ PKIX_PL_AIAMgr *aiaMgr,
+ PKIX_PL_InfoAccess *ia,
+ void **pNBIOContext,
+ PKIX_List **pCerts,
+ void *plContext)
+{
+ PKIX_PL_GeneralName *location = NULL;
+ PKIX_PL_String *locationString = NULL;
+ PKIX_UInt32 len = 0;
+ PRUint16 port = 0;
+ const SEC_HttpClientFcn *httpClient = NULL;
+ const SEC_HttpClientFcnV1 *hcv1 = NULL;
+ SECStatus rv = SECFailure;
+ SEC_HTTP_SERVER_SESSION serverSession = NULL;
+ SEC_HTTP_REQUEST_SESSION requestSession = NULL;
+ char *path = NULL;
+ char *hostname = NULL;
+ char *locationAscii = NULL;
+ void *nbio = NULL;
+ PRUint16 responseCode = 0;
+ const char *responseContentType = NULL;
+ const char *responseData = NULL;
+
+ PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_GetHTTPCerts");
+ PKIX_NULLCHECK_FOUR(aiaMgr, ia, pNBIOContext, pCerts);
+
+ nbio = *pNBIOContext;
+ *pNBIOContext = NULL;
+ *pCerts = NULL;
+
+ if (nbio == NULL) { /* a new request */
+
+ PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation
+ (ia, &location, plContext),
+ PKIX_INFOACCESSGETLOCATIONFAILED);
+
+ /* find or create httpClient = default client */
+ httpClient = SEC_GetRegisteredHttpClient();
+ aiaMgr->client.hdata.httpClient = httpClient;
+ if (!httpClient)
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+
+ if (httpClient->version == 1) {
+
+ PKIX_UInt32 timeout =
+ ((PKIX_PL_NssContext*)plContext)->timeoutSeconds;
+
+ hcv1 = &(httpClient->fcnTable.ftable1);
+
+ /* create server session */
+ PKIX_TOSTRING(location, &locationString, plContext,
+ PKIX_GENERALNAMETOSTRINGFAILED);
+
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ (locationString,
+ PKIX_ESCASCII,
+ (void **)&locationAscii,
+ &len,
+ plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+
+ rv = CERT_ParseURL(locationAscii, &hostname, &port,
+ &path);
+ if ((rv != SECSuccess) ||
+ (hostname == NULL) ||
+ (path == NULL)) {
+ PKIX_ERROR(PKIX_URLPARSINGFAILED);
+ }
+
+ rv = (*hcv1->createSessionFcn)(hostname, port,
+ &serverSession);
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_HTTPCLIENTCREATESESSIONFAILED);
+ }
+
+ aiaMgr->client.hdata.serverSession = serverSession;
+
+ /* create request session */
+ rv = (*hcv1->createFcn)(serverSession, "http", path,
+ "GET", PR_SecondsToInterval(timeout),
+ &requestSession);
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_HTTPSERVERERROR);
+ }
+
+ aiaMgr->client.hdata.requestSession = requestSession;
+ } else {
+ PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
+ }
+ }
+
+ httpClient = aiaMgr->client.hdata.httpClient;
+
+ if (httpClient->version == 1) {
+ PRUint32 responseDataLen =
+ ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
+
+ hcv1 = &(httpClient->fcnTable.ftable1);
+ requestSession = aiaMgr->client.hdata.requestSession;
+
+ /* trySendAndReceive */
+ rv = (*hcv1->trySendAndReceiveFcn)(requestSession,
+ (PRPollDesc **)&nbio,
+ &responseCode,
+ (const char **)&responseContentType,
+ NULL, /* &responseHeaders */
+ (const char **)&responseData,
+ &responseDataLen);
+
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_HTTPSERVERERROR);
+ }
+
+ if (nbio != 0) {
+ *pNBIOContext = nbio;
+ goto cleanup;
+ }
+
+ PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCertResponse
+ (responseCode,
+ responseContentType,
+ responseData,
+ responseDataLen,
+ pCerts,
+ plContext),
+ PKIX_HTTPCERTSTOREPROCESSCERTRESPONSEFAILED);
+
+ /* Session and request cleanup in case of success */
+ if (aiaMgr->client.hdata.requestSession != NULL) {
+ (*hcv1->freeFcn)(aiaMgr->client.hdata.requestSession);
+ aiaMgr->client.hdata.requestSession = NULL;
+ }
+ if (aiaMgr->client.hdata.serverSession != NULL) {
+ (*hcv1->freeSessionFcn)(aiaMgr->client.hdata.serverSession);
+ aiaMgr->client.hdata.serverSession = NULL;
+ }
+ aiaMgr->client.hdata.httpClient = 0; /* callback fn */
+
+ } else {
+ PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
+ }
+
+cleanup:
+ /* Session and request cleanup in case of error. Passing through without cleanup
+ * if interrupted by blocked IO. */
+ if (PKIX_ERROR_RECEIVED) {
+ if (aiaMgr->client.hdata.requestSession != NULL) {
+ (*hcv1->freeFcn)(aiaMgr->client.hdata.requestSession);
+ aiaMgr->client.hdata.requestSession = NULL;
+ }
+ if (aiaMgr->client.hdata.serverSession != NULL) {
+ (*hcv1->freeSessionFcn)(aiaMgr->client.hdata.serverSession);
+ aiaMgr->client.hdata.serverSession = NULL;
+ }
+ aiaMgr->client.hdata.httpClient = 0; /* callback fn */
+ }
+
+ PKIX_DECREF(location);
+ PKIX_DECREF(locationString);
+
+ if (locationAscii) {
+ PORT_Free(locationAscii);
+ }
+ if (hostname) {
+ PORT_Free(hostname);
+ }
+ if (path) {
+ PORT_Free(path);
+ }
+
+ PKIX_RETURN(AIAMGR);
+}
+
+#ifndef NSS_PKIX_NO_LDAP
+PKIX_Error *
+pkix_pl_AIAMgr_GetLDAPCerts(
+ PKIX_PL_AIAMgr *aiaMgr,
+ PKIX_PL_InfoAccess *ia,
+ void **pNBIOContext,
+ PKIX_List **pCerts,
+ void *plContext)
+{
+ PKIX_List *result = NULL;
+ PKIX_PL_GeneralName *location = NULL;
+ PKIX_PL_LdapClient *client = NULL;
+ LDAPRequestParams request;
+ PLArenaPool *arena = NULL;
+ char *domainName = NULL;
+ void *nbio = NULL;
+
+ PKIX_ENTER(AIAMGR, "pkix_pl_AIAMgr_GetLDAPCerts");
+ PKIX_NULLCHECK_FOUR(aiaMgr, ia, pNBIOContext, pCerts);
+
+ nbio = *pNBIOContext;
+ *pNBIOContext = NULL;
+ *pCerts = NULL;
+
+ if (nbio == NULL) { /* a new request */
+
+ /* Initiate an LDAP request */
+
+ request.scope = WHOLE_SUBTREE;
+ request.derefAliases = NEVER_DEREF;
+ request.sizeLimit = 0;
+ request.timeLimit = 0;
+
+ PKIX_CHECK(PKIX_PL_InfoAccess_GetLocation
+ (ia, &location, plContext),
+ PKIX_INFOACCESSGETLOCATIONFAILED);
+
+ /*
+ * Get a short-lived arena. We'll be done with
+ * this space once the request is encoded.
+ */
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!arena) {
+ PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY);
+ }
+
+ PKIX_CHECK(pkix_pl_InfoAccess_ParseLocation
+ (location, arena, &request, &domainName, plContext),
+ PKIX_INFOACCESSPARSELOCATIONFAILED);
+
+ PKIX_DECREF(location);
+
+ /* Find or create a connection to LDAP server */
+ PKIX_CHECK(pkix_pl_AiaMgr_FindLDAPClient
+ (aiaMgr, domainName, &client, plContext),
+ PKIX_AIAMGRFINDLDAPCLIENTFAILED);
+
+ aiaMgr->client.ldapClient = client;
+
+ PKIX_CHECK(PKIX_PL_LdapClient_InitiateRequest
+ (aiaMgr->client.ldapClient,
+ &request,
+ &nbio,
+ &result,
+ plContext),
+ PKIX_LDAPCLIENTINITIATEREQUESTFAILED);
+
+ PKIX_PL_NSSCALL(AIAMGR, PORT_FreeArena, (arena, PR_FALSE));
+
+ } else {
+
+ PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest
+ (aiaMgr->client.ldapClient, &nbio, &result, plContext),
+ PKIX_LDAPCLIENTRESUMEREQUESTFAILED);
+
+ }
+
+ if (nbio != NULL) { /* WOULDBLOCK */
+ *pNBIOContext = nbio;
+ *pCerts = NULL;
+ goto cleanup;
+ }
+
+ PKIX_DECREF(aiaMgr->client.ldapClient);
+
+ if (result == NULL) {
+ *pCerts = NULL;
+ } else {
+ PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList
+ (result, pCerts, plContext),
+ PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED);
+ }
+
+ *pNBIOContext = nbio;
+
+cleanup:
+
+ if (arena && (PKIX_ERROR_RECEIVED)) {
+ PKIX_PL_NSSCALL(AIAMGR, PORT_FreeArena, (arena, PR_FALSE));
+ }
+
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(aiaMgr->client.ldapClient);
+ }
+
+ PKIX_DECREF(location);
+
+ PKIX_RETURN(AIAMGR);
+}
+#endif /* !NSS_PKIX_NO_LDAP */
+
+/*
+ * FUNCTION: PKIX_PL_AIAMgr_Create
+ * DESCRIPTION:
+ *
+ * This function creates an AIAMgr, storing the result at "pAIAMgr".
+ *
+ * PARAMETERS:
+ * "pAIAMGR"
+ * Address at which the returned AIAMgr is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an AIAMgr Error if the function fails in a non-fatal way
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+PKIX_PL_AIAMgr_Create(
+ PKIX_PL_AIAMgr **pAIAMgr,
+ void *plContext)
+{
+ PKIX_PL_AIAMgr *aiaMgr = NULL;
+
+ PKIX_ENTER(AIAMGR, "PKIX_PL_AIAMgr_Create");
+ PKIX_NULLCHECK_ONE(pAIAMgr);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_AIAMGR_TYPE,
+ sizeof(PKIX_PL_AIAMgr),
+ (PKIX_PL_Object **)&aiaMgr,
+ plContext),
+ PKIX_COULDNOTCREATEAIAMGROBJECT);
+ /* pointer to cert cache */
+ /* pointer to crl cache */
+ aiaMgr->method = 0;
+ aiaMgr->aiaIndex = 0;
+ aiaMgr->numAias = 0;
+ aiaMgr->aia = NULL;
+ aiaMgr->location = NULL;
+ aiaMgr->results = NULL;
+ aiaMgr->client.hdata.httpClient = NULL;
+ aiaMgr->client.hdata.serverSession = NULL;
+ aiaMgr->client.hdata.requestSession = NULL;
+
+ *pAIAMgr = aiaMgr;
+
+cleanup:
+
+ PKIX_RETURN(AIAMGR);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_AIAMgr_GetAIACerts (see description in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_AIAMgr_GetAIACerts(
+ PKIX_PL_AIAMgr *aiaMgr,
+ PKIX_PL_Cert *prevCert,
+ void **pNBIOContext,
+ PKIX_List **pCerts,
+ void *plContext)
+{
+ PKIX_UInt32 numAias = 0;
+ PKIX_UInt32 aiaIndex = 0;
+ PKIX_UInt32 iaType = PKIX_INFOACCESS_LOCATION_UNKNOWN;
+ PKIX_List *certs = NULL;
+ PKIX_PL_InfoAccess *ia = NULL;
+ void *nbio = NULL;
+
+ PKIX_ENTER(AIAMGR, "PKIX_PL_AIAMgr_GetAIACerts");
+ PKIX_NULLCHECK_FOUR(aiaMgr, prevCert, pNBIOContext, pCerts);
+
+ nbio = *pNBIOContext;
+ *pCerts = NULL;
+ *pNBIOContext = NULL;
+
+ if (nbio == NULL) { /* a new request */
+
+ /* Does this Cert have an AIA extension? */
+ PKIX_CHECK(PKIX_PL_Cert_GetAuthorityInfoAccess
+ (prevCert, &aiaMgr->aia, plContext),
+ PKIX_CERTGETAUTHORITYINFOACCESSFAILED);
+
+ if (aiaMgr->aia != NULL) {
+ PKIX_CHECK(PKIX_List_GetLength
+ (aiaMgr->aia, &numAias, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+ }
+
+ /* And if so, does it have any entries? */
+ if ((aiaMgr->aia == NULL) || (numAias == 0)) {
+ *pCerts = NULL;
+ goto cleanup;
+ }
+
+ aiaMgr->aiaIndex = 0;
+ aiaMgr->numAias = numAias;
+ aiaMgr->results = NULL;
+
+ }
+
+ for (aiaIndex = aiaMgr->aiaIndex;
+ aiaIndex < aiaMgr->numAias;
+ aiaIndex ++) {
+ PKIX_UInt32 method = 0;
+
+ PKIX_CHECK(PKIX_List_GetItem
+ (aiaMgr->aia,
+ aiaIndex,
+ (PKIX_PL_Object **)&ia,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK(PKIX_PL_InfoAccess_GetMethod
+ (ia, &method, plContext),
+ PKIX_INFOACCESSGETMETHODFAILED);
+
+ if (method != PKIX_INFOACCESS_CA_ISSUERS &&
+ method != PKIX_INFOACCESS_CA_REPOSITORY) {
+ PKIX_DECREF(ia);
+ continue;
+ }
+
+ PKIX_CHECK(PKIX_PL_InfoAccess_GetLocationType
+ (ia, &iaType, plContext),
+ PKIX_INFOACCESSGETLOCATIONTYPEFAILED);
+
+ if (iaType == PKIX_INFOACCESS_LOCATION_HTTP) {
+ PKIX_CHECK(pkix_pl_AIAMgr_GetHTTPCerts
+ (aiaMgr, ia, &nbio, &certs, plContext),
+ PKIX_AIAMGRGETHTTPCERTSFAILED);
+#ifndef NSS_PKIX_NO_LDAP
+ } else if (iaType == PKIX_INFOACCESS_LOCATION_LDAP) {
+ PKIX_CHECK(pkix_pl_AIAMgr_GetLDAPCerts
+ (aiaMgr, ia, &nbio, &certs, plContext),
+ PKIX_AIAMGRGETLDAPCERTSFAILED);
+#endif
+ } else {
+ /* We only support http and ldap requests. */
+ PKIX_DECREF(ia);
+ continue;
+ }
+
+ if (nbio != NULL) { /* WOULDBLOCK */
+ aiaMgr->aiaIndex = aiaIndex;
+ *pNBIOContext = nbio;
+ *pCerts = NULL;
+ goto cleanup;
+ }
+
+ /*
+ * We can't just use and modify the List we received.
+ * Because it's cached, it's set immutable.
+ */
+ if (aiaMgr->results == NULL) {
+ PKIX_CHECK(PKIX_List_Create
+ (&(aiaMgr->results), plContext),
+ PKIX_LISTCREATEFAILED);
+ }
+ PKIX_CHECK(pkix_List_AppendList
+ (aiaMgr->results, certs, plContext),
+ PKIX_APPENDLISTFAILED);
+ PKIX_DECREF(certs);
+
+ PKIX_DECREF(ia);
+ }
+
+ PKIX_DECREF(aiaMgr->aia);
+
+ *pNBIOContext = NULL;
+ *pCerts = aiaMgr->results;
+ aiaMgr->results = NULL;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(aiaMgr->aia);
+ PKIX_DECREF(aiaMgr->results);
+#ifndef NSS_PKIX_NO_LDAP
+ PKIX_DECREF(aiaMgr->client.ldapClient);
+#endif
+ }
+
+ PKIX_DECREF(certs);
+ PKIX_DECREF(ia);
+
+ PKIX_RETURN(AIAMGR);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.h
new file mode 100644
index 000000000..356c1ecdf
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_aiamgr.h
@@ -0,0 +1,65 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_aiamgr.h
+ *
+ * AIAMgr Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_AIAMGR_H
+#define _PKIX_PL_AIAMGR_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_AIAMgrStruct {
+ /* pointer to cert cache */
+ /* pointer to crl cache */
+ PKIX_UInt32 method;
+ PKIX_UInt32 aiaIndex;
+ PKIX_UInt32 numAias;
+ PKIX_List *aia;
+ PKIX_PL_GeneralName *location;
+ PKIX_List *results;
+ union {
+#ifndef NSS_PKIX_NO_LDAP
+ PKIX_PL_LdapClient *ldapClient;
+#endif
+ struct {
+ const SEC_HttpClientFcn *httpClient;
+ SEC_HTTP_SERVER_SESSION serverSession;
+ SEC_HTTP_REQUEST_SESSION requestSession;
+ char *path;
+ } hdata;
+ } client;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_AIAMgr_RegisterSelf(void *plContext);
+
+#ifndef NSS_PKIX_NO_LDAP
+PKIX_Error *PKIX_PL_LdapClient_InitiateRequest(
+ PKIX_PL_LdapClient *client,
+ LDAPRequestParams *requestParams,
+ void **pPollDesc,
+ PKIX_List **pResponse,
+ void *plContext);
+
+PKIX_Error *PKIX_PL_LdapClient_ResumeRequest(
+ PKIX_PL_LdapClient *client,
+ void **pPollDesc,
+ PKIX_List **pResponse,
+ void *plContext);
+#endif /* !NSS_PKIX_NO_LDAP */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_AIAMGR_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.c
new file mode 100755
index 000000000..57004b770
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.c
@@ -0,0 +1,1282 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_colcertstore.c
+ *
+ * CollectionCertStore Function Definitions
+ *
+ */
+
+#include "pkix_pl_colcertstore.h"
+
+/*
+ * This Object is going to be taken out from libpkix SOON. The following
+ * function is copied from nss/cmd library, but not supported by NSS as
+ * public API. We use it since ColCertStore are read in Cert/Crl from
+ * files and need this support.
+ */
+
+static SECStatus
+SECU_FileToItem(SECItem *dst, PRFileDesc *src)
+{
+ PRFileInfo info;
+ PRInt32 numBytes;
+ PRStatus prStatus;
+
+ prStatus = PR_GetOpenFileInfo(src, &info);
+
+ if (prStatus != PR_SUCCESS) {
+ PORT_SetError(SEC_ERROR_IO);
+ return SECFailure;
+ }
+
+ /* XXX workaround for 3.1, not all utils zero dst before sending */
+ dst->data = 0;
+ if (!SECITEM_AllocItem(NULL, dst, info.size))
+ goto loser;
+
+ numBytes = PR_Read(src, dst->data, info.size);
+ if (numBytes != info.size) {
+ PORT_SetError(SEC_ERROR_IO);
+ goto loser;
+ }
+
+ return SECSuccess;
+loser:
+ SECITEM_FreeItem(dst, PR_FALSE);
+ return SECFailure;
+}
+
+static SECStatus
+SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii)
+{
+ SECStatus rv;
+ if (ascii) {
+ /* First convert ascii to binary */
+ SECItem filedata;
+ char *asc, *body;
+
+ /* Read in ascii data */
+ rv = SECU_FileToItem(&filedata, inFile);
+ asc = (char *)filedata.data;
+ if (!asc) {
+ fprintf(stderr, "unable to read data from input file\n");
+ return SECFailure;
+ }
+
+ /* check for headers and trailers and remove them */
+ if ((body = strstr(asc, "-----BEGIN")) != NULL) {
+ char *trailer = NULL;
+ asc = body;
+ body = PORT_Strchr(body, '\n');
+ if (!body)
+ body = PORT_Strchr(asc, '\r'); /* maybe this is a MAC file */
+ if (body)
+ trailer = strstr(++body, "-----END");
+ if (trailer != NULL) {
+ *trailer = '\0';
+ } else {
+ fprintf(stderr, "input has header but no trailer\n");
+ PORT_Free(filedata.data);
+ return SECFailure;
+ }
+ } else {
+ body = asc;
+ }
+
+ /* Convert to binary */
+ rv = ATOB_ConvertAsciiToItem(der, body);
+ if (rv) {
+ return SECFailure;
+ }
+
+ PORT_Free(filedata.data);
+ } else {
+ /* Read in binary der */
+ rv = SECU_FileToItem(der, inFile);
+ if (rv) {
+ return SECFailure;
+ }
+ }
+ return SECSuccess;
+}
+
+/*
+ * FUNCTION: PKIX_PL_CollectionCertStoreContext_Create
+ * DESCRIPTION:
+ *
+ * Creates a new CollectionCertStoreContext using the String pointed to
+ * by "storeDir" and stores it at "pColCertStoreContext".
+ *
+ * PARAMETERS:
+ * "storeDir"
+ * The absolute path where *.crl and *.crt files are located.
+ * "pColCertStoreContext"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CollectionCertStoreContext Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_Create(
+ PKIX_PL_String *storeDir,
+ PKIX_PL_CollectionCertStoreContext **pColCertStoreContext,
+ void *plContext)
+{
+ PKIX_PL_CollectionCertStoreContext *colCertStoreContext = NULL;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_Create");
+ PKIX_NULLCHECK_TWO(storeDir, pColCertStoreContext);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_COLLECTIONCERTSTORECONTEXT_TYPE,
+ sizeof (PKIX_PL_CollectionCertStoreContext),
+ (PKIX_PL_Object **)&colCertStoreContext,
+ plContext),
+ PKIX_COULDNOTCREATECOLLECTIONCERTSTORECONTEXTOBJECT);
+
+ PKIX_INCREF(storeDir);
+ colCertStoreContext->storeDir = storeDir;
+
+ colCertStoreContext->crlList = NULL;
+ colCertStoreContext->certList = NULL;
+
+ *pColCertStoreContext = colCertStoreContext;
+ colCertStoreContext = NULL;
+
+cleanup:
+
+ PKIX_DECREF(colCertStoreContext);
+
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_CollectionCertStoreContext *colCertStoreContext = NULL;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_COLLECTIONCERTSTORECONTEXT_TYPE, plContext),
+ PKIX_OBJECTNOTCOLLECTIONCERTSTORECONTEXT);
+
+ colCertStoreContext = (PKIX_PL_CollectionCertStoreContext *)object;
+
+ PKIX_DECREF(colCertStoreContext->storeDir);
+ PKIX_DECREF(colCertStoreContext->crlList);
+ PKIX_DECREF(colCertStoreContext->certList);
+
+cleanup:
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_CollectionCertStoreContext *collectionCSContext = NULL;
+ PKIX_UInt32 tempHash = 0;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType
+ (object,
+ PKIX_COLLECTIONCERTSTORECONTEXT_TYPE,
+ plContext),
+ PKIX_OBJECTNOTCOLLECTIONCERTSTORECONTEXT);
+
+ collectionCSContext = (PKIX_PL_CollectionCertStoreContext *)object;
+
+ PKIX_CHECK(PKIX_PL_Object_Hashcode
+ ((PKIX_PL_Object *) collectionCSContext->storeDir,
+ &tempHash,
+ plContext),
+ PKIX_STRINGHASHCODEFAILED);
+
+ *pHashcode = tempHash << 7;
+
+ /* should not hash on crlList and certList, values are dynamic */
+
+cleanup:
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_Equals
+ * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Int32 *pResult,
+ void *plContext)
+{
+ PKIX_PL_CollectionCertStoreContext *firstCCSContext = NULL;
+ PKIX_PL_CollectionCertStoreContext *secondCCSContext = NULL;
+ PKIX_Boolean cmpResult = 0;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ PKIX_CHECK(pkix_CheckTypes
+ (firstObject,
+ secondObject,
+ PKIX_COLLECTIONCERTSTORECONTEXT_TYPE,
+ plContext),
+ PKIX_OBJECTNOTCOLLECTIONCERTSTORECONTEXT);
+
+ firstCCSContext = (PKIX_PL_CollectionCertStoreContext *)firstObject;
+ secondCCSContext = (PKIX_PL_CollectionCertStoreContext *)secondObject;
+
+ if (firstCCSContext->storeDir == secondCCSContext->storeDir) {
+
+ cmpResult = PKIX_TRUE;
+
+ } else {
+
+ PKIX_CHECK(PKIX_PL_Object_Equals
+ ((PKIX_PL_Object *) firstCCSContext->storeDir,
+ (PKIX_PL_Object *) secondCCSContext->storeDir,
+ &cmpResult,
+ plContext),
+ PKIX_STRINGEQUALSFAILED);
+ }
+
+ *pResult = cmpResult;
+
+ /* should not check equal on crlList and certList, data are dynamic */
+
+cleanup:
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStore_CheckTrust
+ * DESCRIPTION:
+ * This function checks the trust status of this "cert" that was retrieved
+ * from the CertStore "store" and returns its trust status at "pTrusted".
+ *
+ * PARAMETERS:
+ * "store"
+ * Address of the CertStore. Must be non-NULL.
+ * "cert"
+ * Address of the Cert. Must be non-NULL.
+ * "pTrusted"
+ * Address of PKIX_Boolean where the "cert" trust status is returned.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStore_CheckTrust(
+ PKIX_CertStore *store,
+ PKIX_PL_Cert *cert,
+ PKIX_Boolean *pTrusted,
+ void *plContext)
+{
+ PKIX_ENTER(CERTSTORE, "pkix_pl_CollectionCertStore_CheckTrust");
+ PKIX_NULLCHECK_THREE(store, cert, pTrusted);
+
+ *pTrusted = PKIX_TRUE;
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_CreateCert
+ * DESCRIPTION:
+ *
+ * Creates Cert using data file path name pointed to by "certFileName" and
+ * stores it at "pCert". If the Cert can not be decoded, NULL is stored
+ * at "pCert".
+ *
+ * PARAMETERS
+ * "certFileName" - Address of Cert data file path name. Must be non-NULL.
+ * "pCert" - Address where object pointer will be stored. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CollectionCertStoreContext Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_CreateCert(
+ const char *certFileName,
+ PKIX_PL_Cert **pCert,
+ void *plContext)
+{
+ PKIX_PL_ByteArray *byteArray = NULL;
+ PKIX_PL_Cert *cert = NULL;
+ PRFileDesc *inFile = NULL;
+ SECItem certDER;
+ void *buf = NULL;
+ PKIX_UInt32 len;
+ SECStatus rv;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_CreateCert");
+ PKIX_NULLCHECK_TWO(certFileName, pCert);
+
+ *pCert = NULL;
+ certDER.data = NULL;
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_Open.\n");
+ inFile = PR_Open(certFileName, PR_RDONLY, 0);
+
+ if (!inFile){
+ PKIX_ERROR(PKIX_UNABLETOOPENCERTFILE);
+ } else {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling SECU_ReadDerFromFile.\n");
+ rv = SECU_ReadDERFromFile(&certDER, inFile, PR_FALSE);
+ if (!rv){
+ buf = (void *)certDER.data;
+ len = certDER.len;
+
+ PKIX_CHECK(PKIX_PL_ByteArray_Create
+ (buf, len, &byteArray, plContext),
+ PKIX_BYTEARRAYCREATEFAILED);
+
+ PKIX_CHECK(PKIX_PL_Cert_Create
+ (byteArray, &cert, plContext),
+ PKIX_CERTCREATEFAILED);
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling SECITEM_FreeItem.\n");
+ SECITEM_FreeItem(&certDER, PR_FALSE);
+
+ } else {
+ PKIX_ERROR(PKIX_UNABLETOREADDERFROMCERTFILE);
+ }
+ }
+
+ *pCert = cert;
+
+cleanup:
+ if (inFile){
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_CloseDir.\n");
+ PR_Close(inFile);
+ }
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling SECITEM_FreeItem).\n");
+ SECITEM_FreeItem(&certDER, PR_FALSE);
+
+ PKIX_DECREF(cert);
+ }
+ PKIX_DECREF(byteArray);
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_CreateCRL
+ * DESCRIPTION:
+ *
+ * Creates CRL using data file path name pointed to by "crlFileName" and
+ * stores it at "pCrl". If the CRL can not be decoded, NULL is stored
+ * at "pCrl".
+ *
+ * PARAMETERS
+ * "crlFileName" - Address of CRL data file path name. Must be non-NULL.
+ * "pCrl" - Address where object pointer will be stored. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CollectionCertStoreContext Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_CreateCRL(
+ const char *crlFileName,
+ PKIX_PL_CRL **pCrl,
+ void *plContext)
+{
+ PKIX_PL_ByteArray *byteArray = NULL;
+ PKIX_PL_CRL *crl = NULL;
+ PRFileDesc *inFile = NULL;
+ SECItem crlDER;
+ void *buf = NULL;
+ PKIX_UInt32 len;
+ SECStatus rv;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_CreateCRL");
+ PKIX_NULLCHECK_TWO(crlFileName, pCrl);
+
+ *pCrl = NULL;
+ crlDER.data = NULL;
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_Open.\n");
+ inFile = PR_Open(crlFileName, PR_RDONLY, 0);
+
+ if (!inFile){
+ PKIX_ERROR(PKIX_UNABLETOOPENCRLFILE);
+ } else {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling SECU_ReadDerFromFile.\n");
+ rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE);
+ if (!rv){
+ buf = (void *)crlDER.data;
+ len = crlDER.len;
+
+ PKIX_CHECK(PKIX_PL_ByteArray_Create
+ (buf, len, &byteArray, plContext),
+ PKIX_BYTEARRAYCREATEFAILED);
+
+ PKIX_CHECK(PKIX_PL_CRL_Create
+ (byteArray, &crl, plContext),
+ PKIX_CRLCREATEFAILED);
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling SECITEM_FreeItem.\n");
+ SECITEM_FreeItem(&crlDER, PR_FALSE);
+
+ } else {
+ PKIX_ERROR(PKIX_UNABLETOREADDERFROMCRLFILE);
+ }
+ }
+
+ *pCrl = crl;
+
+cleanup:
+ if (inFile){
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_CloseDir.\n");
+ PR_Close(inFile);
+ }
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling SECITEM_FreeItem).\n");
+ SECITEM_FreeItem(&crlDER, PR_FALSE);
+
+ PKIX_DECREF(crl);
+ if (crlDER.data != NULL) {
+ SECITEM_FreeItem(&crlDER, PR_FALSE);
+ }
+ }
+
+ PKIX_DECREF(byteArray);
+
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_PopulateCert
+ * DESCRIPTION:
+ *
+ * Create list of Certs from *.crt files at directory specified in dirName,
+ * Not recursive to sub-directory. Also assume the directory contents are
+ * not changed dynamically.
+ *
+ * PARAMETERS
+ * "colCertStoreContext" - Address of CollectionCertStoreContext
+ * where the dirName is specified and where the return
+ * Certs are stored as a list. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Not Thread Safe - A lock at top level is required.
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CollectionCertStoreContext Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_PopulateCert(
+ PKIX_PL_CollectionCertStoreContext *colCertStoreContext,
+ void *plContext)
+{
+ PKIX_List *certList = NULL;
+ PKIX_PL_Cert *certItem = NULL;
+ char *dirName = NULL;
+ char *pathName = NULL;
+ PKIX_UInt32 dirNameLen = 0;
+ PRErrorCode prError = 0;
+ PRDir *dir = NULL;
+ PRDirEntry *dirEntry = NULL;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_PopulateCert");
+ PKIX_NULLCHECK_ONE(colCertStoreContext);
+
+ /* convert directory to ascii */
+
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ (colCertStoreContext->storeDir,
+ PKIX_ESCASCII,
+ (void **)&dirName,
+ &dirNameLen,
+ plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+
+ /* create cert list, if no cert file, should return an empty list */
+
+ PKIX_CHECK(PKIX_List_Create(&certList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ /* open directory and read in .crt files */
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_OpenDir.\n");
+ dir = PR_OpenDir(dirName);
+
+ if (!dir) {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG_ARG
+ ("\t\t Directory Name:%s\n", dirName);
+ PKIX_ERROR(PKIX_CANNOTOPENCOLLECTIONCERTSTORECONTEXTDIRECTORY);
+ }
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_ReadDir.\n");
+ dirEntry = PR_ReadDir(dir, PR_SKIP_HIDDEN | PR_SKIP_BOTH);
+
+ if (!dirEntry) {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Empty directory.\n");
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_GetError.\n");
+ prError = PR_GetError();
+ }
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_SetError.\n");
+ PR_SetError(0, 0);
+
+ while (dirEntry != NULL && prError == 0) {
+ if (PL_strrstr(dirEntry->name, ".crt") ==
+ dirEntry->name + PL_strlen(dirEntry->name) - 4) {
+
+ PKIX_CHECK_ONLY_FATAL
+ (PKIX_PL_Malloc
+ (dirNameLen + PL_strlen(dirEntry->name) + 2,
+ (void **)&pathName,
+ plContext),
+ PKIX_MALLOCFAILED);
+
+ if ((!PKIX_ERROR_RECEIVED) && (pathName != NULL)){
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PL_strcpy for dirName.\n");
+ PL_strcpy(pathName, dirName);
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PL_strcat for dirName.\n");
+ PL_strcat(pathName, "/");
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PL_strcat for /.\n");
+ PL_strcat(pathName, dirEntry->name);
+
+ PKIX_CHECK_ONLY_FATAL
+ (pkix_pl_CollectionCertStoreContext_CreateCert
+ (pathName, &certItem, plContext),
+ PKIX_COLLECTIONCERTSTORECONTEXTCREATECERTFAILED);
+
+ if (!PKIX_ERROR_RECEIVED){
+ PKIX_CHECK_ONLY_FATAL
+ (PKIX_List_AppendItem
+ (certList,
+ (PKIX_PL_Object *)certItem,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ }
+ }
+
+ PKIX_DECREF(certItem);
+ PKIX_FREE(pathName);
+ }
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_SetError.\n");
+ PR_SetError(0, 0);
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_ReadDir.\n");
+ dirEntry = PR_ReadDir(dir, PR_SKIP_HIDDEN | PR_SKIP_BOTH);
+
+ if (!dirEntry) {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_GetError.\n");
+ prError = PR_GetError();
+ }
+ }
+
+ if ((prError != 0) && (prError != PR_NO_MORE_FILES_ERROR)) {
+ PKIX_ERROR(PKIX_COLLECTIONCERTSTOREPOPULATECERTFAILED);
+ }
+
+ PKIX_CHECK(PKIX_List_SetImmutable(certList, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ PKIX_INCREF(certList);
+ colCertStoreContext->certList = certList;
+
+cleanup:
+ if (dir) {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_CloseDir.\n");
+ PR_CloseDir(dir);
+ }
+
+ PKIX_FREE(pathName);
+ PKIX_FREE(dirName);
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(certList);
+ }
+
+ PKIX_DECREF(certItem);
+ PKIX_DECREF(certList);
+
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_PopulateCRL
+ * DESCRIPTION:
+ *
+ * Create list of CRLs from *.crl files at directory specified in dirName,
+ * Not recursive to sub-dirctory. Also assume the directory contents are
+ * not changed dynamically.
+ *
+ * PARAMETERS
+ * "colCertStoreContext" - Address of CollectionCertStoreContext
+ * where the dirName is specified and where the return
+ * CRLs are stored as a list. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Not Thread Safe - A lock at top level is required.
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CollectionCertStoreContext Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_PopulateCRL(
+ PKIX_PL_CollectionCertStoreContext *colCertStoreContext,
+ void *plContext)
+{
+ PKIX_List *crlList = NULL;
+ PKIX_PL_CRL *crlItem = NULL;
+ char *dirName = NULL;
+ char *pathName = NULL;
+ PKIX_UInt32 dirNameLen = 0;
+ PRErrorCode prError = 0;
+ PRDir *dir = NULL;
+ PRDirEntry *dirEntry = NULL;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_PopulateCRL");
+ PKIX_NULLCHECK_ONE(colCertStoreContext);
+
+ /* convert directory to ascii */
+
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ (colCertStoreContext->storeDir,
+ PKIX_ESCASCII,
+ (void **)&dirName,
+ &dirNameLen,
+ plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+
+ /* create CRL list, if no CRL file, should return an empty list */
+
+ PKIX_CHECK(PKIX_List_Create(&crlList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ /* open directory and read in .crl files */
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_OpenDir.\n");
+ dir = PR_OpenDir(dirName);
+
+ if (!dir) {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG_ARG
+ ("\t\t Directory Name:%s\n", dirName);
+ PKIX_ERROR(PKIX_CANNOTOPENCOLLECTIONCERTSTORECONTEXTDIRECTORY);
+ }
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_ReadDir.\n");
+ dirEntry = PR_ReadDir(dir, PR_SKIP_HIDDEN | PR_SKIP_BOTH);
+
+ if (!dirEntry) {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Empty directory.\n");
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_GetError.\n");
+ prError = PR_GetError();
+ }
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG("\t\t Calling PR_SetError.\n");
+ PR_SetError(0, 0);
+
+ while (dirEntry != NULL && prError == 0) {
+ if (PL_strrstr(dirEntry->name, ".crl") ==
+ dirEntry->name + PL_strlen(dirEntry->name) - 4) {
+
+ PKIX_CHECK_ONLY_FATAL
+ (PKIX_PL_Malloc
+ (dirNameLen + PL_strlen(dirEntry->name) + 2,
+ (void **)&pathName,
+ plContext),
+ PKIX_MALLOCFAILED);
+
+ if ((!PKIX_ERROR_RECEIVED) && (pathName != NULL)){
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PL_strcpy for dirName.\n");
+ PL_strcpy(pathName, dirName);
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PL_strcat for dirName.\n");
+ PL_strcat(pathName, "/");
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PL_strcat for /.\n");
+ PL_strcat(pathName, dirEntry->name);
+
+ PKIX_CHECK_ONLY_FATAL
+ (pkix_pl_CollectionCertStoreContext_CreateCRL
+ (pathName, &crlItem, plContext),
+ PKIX_COLLECTIONCERTSTORECONTEXTCREATECRLFAILED);
+
+ if (!PKIX_ERROR_RECEIVED){
+ PKIX_CHECK_ONLY_FATAL
+ (PKIX_List_AppendItem
+ (crlList,
+ (PKIX_PL_Object *)crlItem,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ }
+ }
+
+ PKIX_DECREF(crlItem);
+ PKIX_FREE(pathName);
+ }
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_SetError.\n");
+ PR_SetError(0, 0);
+
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_ReadDir.\n");
+ dirEntry = PR_ReadDir(dir, PR_SKIP_HIDDEN | PR_SKIP_BOTH);
+
+ if (!dirEntry) {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_GetError.\n");
+ prError = PR_GetError();
+ }
+ }
+
+ if ((prError != 0) && (prError != PR_NO_MORE_FILES_ERROR)) {
+ PKIX_ERROR(PKIX_COLLECTIONCERTSTORECONTEXTGETSELECTCRLFAILED);
+ }
+
+ PKIX_CHECK(PKIX_List_SetImmutable(crlList, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ PKIX_INCREF(crlList);
+ colCertStoreContext->crlList = crlList;
+
+cleanup:
+ if (dir) {
+ PKIX_COLLECTIONCERTSTORECONTEXT_DEBUG
+ ("\t\t Calling PR_CloseDir.\n");
+ PR_CloseDir(dir);
+ }
+
+ PKIX_FREE(pathName);
+ PKIX_FREE(dirName);
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(crlList);
+ }
+
+ PKIX_DECREF(crlItem);
+ PKIX_DECREF(crlList);
+
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_GetSelectedCert
+ * DESCRIPTION:
+ *
+ * Finds the Certs that match the criterion of the CertSelector pointed
+ * to by "selector" using the List of Certs pointed to by "certList" and
+ * stores the matching Certs at "pSelectedCertList".
+ *
+ * Not recursive to sub-directory.
+ *
+ * PARAMETERS
+ * "certList" - Address of List of Certs to be searched. Must be non-NULL.
+ * "colCertStoreContext" - Address of CollectionCertStoreContext
+ * where the cached Certs are stored.
+ * "selector" - CertSelector for chosing Cert based on Params set
+ * "pSelectedCertList" - Certs that qualified by selector.
+ * "plContext" - Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Not Thread Safe - A lock at top level is required.
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CollectionCertStoreContext Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_GetSelectedCert(
+ PKIX_List *certList,
+ PKIX_CertSelector *selector,
+ PKIX_List **pSelectedCertList,
+ void *plContext)
+{
+ PKIX_List *selectCertList = NULL;
+ PKIX_PL_Cert *certItem = NULL;
+ PKIX_CertSelector_MatchCallback certSelectorMatch = NULL;
+ PKIX_UInt32 numCerts = 0;
+ PKIX_UInt32 i = 0;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_GetSelectedCert");
+ PKIX_NULLCHECK_THREE(certList, selector, pSelectedCertList);
+
+ PKIX_CHECK(PKIX_CertSelector_GetMatchCallback
+ (selector, &certSelectorMatch, plContext),
+ PKIX_CERTSELECTORGETMATCHCALLBACKFAILED);
+
+ PKIX_CHECK(PKIX_List_GetLength(certList, &numCerts, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ if (certSelectorMatch) {
+
+ PKIX_CHECK(PKIX_List_Create(&selectCertList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ for (i = 0; i < numCerts; i++) {
+ PKIX_CHECK_ONLY_FATAL
+ (PKIX_List_GetItem
+ (certList,
+ i,
+ (PKIX_PL_Object **) &certItem,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ if (!PKIX_ERROR_RECEIVED){
+ PKIX_CHECK_ONLY_FATAL
+ (certSelectorMatch
+ (selector, certItem, plContext),
+ PKIX_CERTSELECTORMATCHFAILED);
+
+ if (!PKIX_ERROR_RECEIVED){
+ PKIX_CHECK_ONLY_FATAL
+ (PKIX_List_AppendItem
+ (selectCertList,
+ (PKIX_PL_Object *)certItem,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ }
+ }
+
+ PKIX_DECREF(certItem);
+ }
+
+ } else {
+
+ PKIX_INCREF(certList);
+
+ selectCertList = certList;
+ }
+
+ *pSelectedCertList = selectCertList;
+
+cleanup:
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_GetSelectedCRL
+ * DESCRIPTION:
+ *
+ * Finds the CRLs that match the criterion of the CRLSelector pointed
+ * to by "selector" using the List of CRLs pointed to by "crlList" and
+ * stores the matching CRLs at "pSelectedCrlList".
+ *
+ * Not recursive to sub-directory.
+ *
+ * PARAMETERS
+ * "crlList" - Address of List of CRLs to be searched. Must be non-NULL
+ * "selector" - CRLSelector for chosing CRL based on Params set
+ * "pSelectedCrlList" - CRLs that qualified by selector.
+ * "plContext" - Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Not Thread Safe - A lock at top level is required.
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CollectionCertStoreContext Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CollectionCertStoreContext_GetSelectedCRL(
+ PKIX_List *crlList,
+ PKIX_CRLSelector *selector,
+ PKIX_List **pSelectedCrlList,
+ void *plContext)
+{
+ PKIX_List *selectCrlList = NULL;
+ PKIX_PL_CRL *crlItem = NULL;
+ PKIX_CRLSelector_MatchCallback crlSelectorMatch = NULL;
+ PKIX_UInt32 numCrls = 0;
+ PKIX_UInt32 i = 0;
+ PKIX_Boolean match = PKIX_FALSE;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_GetSelectedCRL");
+ PKIX_NULLCHECK_THREE(crlList, selector, pSelectedCrlList);
+
+ PKIX_CHECK(PKIX_CRLSelector_GetMatchCallback
+ (selector, &crlSelectorMatch, plContext),
+ PKIX_CRLSELECTORGETMATCHCALLBACKFAILED);
+
+ PKIX_CHECK(PKIX_List_GetLength(crlList, &numCrls, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ if (crlSelectorMatch) {
+
+ PKIX_CHECK(PKIX_List_Create(&selectCrlList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ for (i = 0; i < numCrls; i++) {
+ PKIX_CHECK_ONLY_FATAL(PKIX_List_GetItem
+ (crlList,
+ i,
+ (PKIX_PL_Object **) &crlItem,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ if (!PKIX_ERROR_RECEIVED){
+ PKIX_CHECK_ONLY_FATAL
+ (crlSelectorMatch
+ (selector, crlItem, &match, plContext),
+ PKIX_CRLSELECTORMATCHFAILED);
+
+ if (!(PKIX_ERROR_RECEIVED) && match) {
+ PKIX_CHECK_ONLY_FATAL
+ (PKIX_List_AppendItem
+ (selectCrlList,
+ (PKIX_PL_Object *)crlItem,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ }
+ }
+
+ PKIX_DECREF(crlItem);
+ }
+ } else {
+
+ PKIX_INCREF(crlList);
+
+ selectCrlList = crlList;
+ }
+
+ /* Don't throw away the list if one CRL was bad! */
+ pkixTempErrorReceived = PKIX_FALSE;
+
+ *pSelectedCrlList = selectCrlList;
+
+cleanup:
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStore_GetCert
+ * DESCRIPTION:
+ *
+ * Retrieve Certs in a list of PKIX_PL_Cert object.
+ *
+ * PARAMETERS:
+ * "colCertStoreContext"
+ * The object CertStore is the object passed in by checker call.
+ * "crlSelector"
+ * CRLSelector specifies criteria for chosing CRL's
+ * "pNBIOContext"
+ * Address where platform-dependent information is returned for CertStores
+ * that use non-blocking I/O. Must be non-NULL.
+ * "pCertList"
+ * Address where object pointer will be returned. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_CollectionCertStore_GetCert(
+ PKIX_CertStore *certStore,
+ PKIX_CertSelector *selector,
+ PKIX_VerifyNode *verifyNode,
+ void **pNBIOContext,
+ PKIX_List **pCerts,
+ void *plContext)
+{
+ PKIX_PL_CollectionCertStoreContext *colCertStoreContext = NULL;
+ PKIX_List *selectedCerts = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_CollectionCertStore_GetCert");
+ PKIX_NULLCHECK_FOUR(certStore, selector, pNBIOContext, pCerts);
+
+ *pNBIOContext = NULL; /* We don't use non-blocking I/O */
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
+ (certStore,
+ (PKIX_PL_Object **) &colCertStoreContext,
+ plContext),
+ PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
+
+ if (colCertStoreContext->certList == NULL) {
+
+ PKIX_OBJECT_LOCK(colCertStoreContext);
+
+ /*
+ * Certs in the directory are cached based on the
+ * assumption that the directory contents won't be
+ * changed dynamically.
+ */
+ if (colCertStoreContext->certList == NULL){
+ PKIX_CHECK(pkix_pl_CollectionCertStoreContext_PopulateCert
+ (colCertStoreContext, plContext),
+ PKIX_COLLECTIONCERTSTORECONTEXTPOPULATECERTFAILED);
+ }
+
+ PKIX_OBJECT_UNLOCK(colCertStoreContext);
+ }
+
+ PKIX_CHECK(pkix_pl_CollectionCertStoreContext_GetSelectedCert
+ (colCertStoreContext->certList,
+ selector,
+ &selectedCerts,
+ plContext),
+ PKIX_COLLECTIONCERTSTORECONTEXTGETSELECTCERTFAILED);
+
+ *pCerts = selectedCerts;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ PKIX_DECREF(colCertStoreContext);
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStore_GetCRL
+ * DESCRIPTION:
+ *
+ * Retrieve CRL's in a list of PKIX_PL_CRL object.
+ *
+ * PARAMETERS:
+ * "colCertStoreContext"
+ * The object CertStore is passed in by checker call.
+ * "crlSelector"
+ * CRLSelector specifies criteria for chosing CRL's
+ * "pNBIOContext"
+ * Address where platform-dependent information is returned for CertStores
+ * that use non-blocking I/O. Must be non-NULL.
+ * "pCrlList"
+ * Address where object pointer will be returned. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_CollectionCertStore_GetCRL(
+ PKIX_CertStore *certStore,
+ PKIX_CRLSelector *selector,
+ void **pNBIOContext,
+ PKIX_List **pCrlList,
+ void *plContext)
+{
+ PKIX_PL_CollectionCertStoreContext *colCertStoreContext = NULL;
+ PKIX_List *selectCrl = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_CollectionCertStore_GetCRL");
+ PKIX_NULLCHECK_FOUR(certStore, selector, pNBIOContext, pCrlList);
+
+ *pNBIOContext = NULL; /* We don't use non-blocking I/O */
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
+ (certStore,
+ (PKIX_PL_Object **) &colCertStoreContext,
+ plContext),
+ PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
+
+ if (colCertStoreContext->crlList == NULL) {
+
+ PKIX_OBJECT_LOCK(colCertStoreContext);
+
+ /*
+ * CRLs in the directory are cached based on the
+ * assumption that the directory contents won't be
+ * changed dynamically.
+ */
+ if (colCertStoreContext->crlList == NULL){
+ PKIX_CHECK(pkix_pl_CollectionCertStoreContext_PopulateCRL
+ (colCertStoreContext, plContext),
+ PKIX_COLLECTIONCERTSTORECONTEXTPOPULATECRLFAILED);
+ }
+
+ PKIX_OBJECT_UNLOCK(colCertStoreContext);
+
+ }
+
+ PKIX_CHECK(pkix_pl_CollectionCertStoreContext_GetSelectedCRL
+ (colCertStoreContext->crlList,
+ selector,
+ &selectCrl,
+ plContext),
+ PKIX_COLLECTIONCERTSTORECONTEXTGETSELECTCRLFAILED);
+
+ *pCrlList = selectCrl;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ PKIX_DECREF(colCertStoreContext);
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_CollectionCertStoreContext_RegisterSelf
+ * DESCRIPTION:
+ *
+ * Registers PKIX_PL_COLLECTIONCERTSTORECONTEXT_TYPE and its related
+ * functions with systemClasses[]
+ *
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_CollectionCertStoreContext_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(COLLECTIONCERTSTORECONTEXT,
+ "pkix_pl_CollectionCertStoreContext_RegisterSelf");
+
+ entry.description = "CollectionCertStoreContext";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_CollectionCertStoreContext);
+ entry.destructor = pkix_pl_CollectionCertStoreContext_Destroy;
+ entry.equalsFunction = pkix_pl_CollectionCertStoreContext_Equals;
+ entry.hashcodeFunction = pkix_pl_CollectionCertStoreContext_Hashcode;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = NULL;
+
+ systemClasses[PKIX_COLLECTIONCERTSTORECONTEXT_TYPE] = entry;
+
+ PKIX_RETURN(COLLECTIONCERTSTORECONTEXT);
+}
+
+/* --Public-CollectionCertStoreContext-Functions--------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_CollectionCertStore_Create
+ * (see comments in pkix_samples_modules.h)
+ */
+PKIX_Error *
+PKIX_PL_CollectionCertStore_Create(
+ PKIX_PL_String *storeDir,
+ PKIX_CertStore **pCertStore,
+ void *plContext)
+{
+ PKIX_PL_CollectionCertStoreContext *colCertStoreContext = NULL;
+ PKIX_CertStore *certStore = NULL;
+
+ PKIX_ENTER(CERTSTORE, "PKIX_PL_CollectionCertStore_Create");
+ PKIX_NULLCHECK_TWO(storeDir, pCertStore);
+
+ PKIX_CHECK(pkix_pl_CollectionCertStoreContext_Create
+ (storeDir, &colCertStoreContext, plContext),
+ PKIX_COULDNOTCREATECOLLECTIONCERTSTORECONTEXTOBJECT);
+
+ PKIX_CHECK(PKIX_CertStore_Create
+ (pkix_pl_CollectionCertStore_GetCert,
+ pkix_pl_CollectionCertStore_GetCRL,
+ NULL, /* GetCertContinue */
+ NULL, /* GetCRLContinue */
+ pkix_pl_CollectionCertStore_CheckTrust,
+ NULL, /* can not store crls */
+ NULL, /* can not do revocation check */
+ (PKIX_PL_Object *)colCertStoreContext,
+ PKIX_TRUE, /* cache flag */
+ PKIX_TRUE, /* local - no network I/O */
+ &certStore,
+ plContext),
+ PKIX_CERTSTORECREATEFAILED);
+
+ PKIX_DECREF(colCertStoreContext);
+
+ *pCertStore = certStore;
+
+cleanup:
+ PKIX_RETURN(CERTSTORE);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.h
new file mode 100755
index 000000000..f41e6fa5e
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_colcertstore.h
@@ -0,0 +1,34 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_colcertstore.h
+ *
+ * CollectionCertstore Object Type Definition
+ *
+ */
+
+#ifndef _PKIX_PL_COLCERTSTORE_H
+#define _PKIX_PL_COLCERTSTORE_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_CollectionCertStoreContext {
+ PKIX_PL_String *storeDir;
+ PKIX_List *crlList;
+ PKIX_List *certList;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_CollectionCertStoreContext_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_COLCERTSTORE_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c
new file mode 100755
index 000000000..471f92004
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.c
@@ -0,0 +1,1147 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_httpcertstore.c
+ *
+ * HTTPCertStore Function Definitions
+ *
+ */
+
+/* We can't decode the length of a message without at least this many bytes */
+
+#include "pkix_pl_httpcertstore.h"
+extern PKIX_PL_HashTable *httpSocketCache;
+SEC_ASN1_MKSUB(CERT_IssuerAndSNTemplate)
+SEC_ASN1_MKSUB(SECOID_AlgorithmIDTemplate)
+SEC_ASN1_MKSUB(SEC_SetOfAnyTemplate)
+SEC_ASN1_MKSUB(CERT_SetOfSignedCrlTemplate)
+
+SEC_ASN1_CHOOSER_DECLARE(CERT_IssuerAndSNTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SECOID_AlgorithmIDTemplate)
+/* SEC_ASN1_CHOOSER_DECLARE(SEC_SetOfAnyTemplate)
+SEC_ASN1_CHOOSER_DECLARE(CERT_SetOfSignedCrlTemplate)
+
+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 }
+};
+
+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 }
+}; */
+
+/* --Private-HttpCertStoreContext-Object Functions----------------------- */
+
+/*
+ * FUNCTION: pkix_pl_HttpCertStoreContext_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_HttpCertStoreContext_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ const SEC_HttpClientFcnV1 *hcv1 = NULL;
+ PKIX_PL_HttpCertStoreContext *context = NULL;
+
+ PKIX_ENTER
+ (HTTPCERTSTORECONTEXT, "pkix_pl_HttpCertStoreContext_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_HTTPCERTSTORECONTEXT_TYPE, plContext),
+ PKIX_OBJECTNOTANHTTPCERTSTORECONTEXT);
+
+ context = (PKIX_PL_HttpCertStoreContext *)object;
+ hcv1 = (const SEC_HttpClientFcnV1 *)(context->client);
+ if (context->requestSession != NULL) {
+ (*hcv1->freeFcn)(context->requestSession);
+ context->requestSession = NULL;
+ }
+ if (context->serverSession != NULL) {
+ (*hcv1->freeSessionFcn)(context->serverSession);
+ context->serverSession = NULL;
+ }
+ if (context->path != NULL) {
+ PORT_Free(context->path);
+ context->path = NULL;
+ }
+
+cleanup:
+
+ PKIX_RETURN(HTTPCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpCertStoreContext_RegisterSelf
+ *
+ * DESCRIPTION:
+ * Registers PKIX_PL_HTTPCERTSTORECONTEXT_TYPE and its related
+ * functions with systemClasses[]
+ *
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_HttpCertStoreContext_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry *entry = &systemClasses[PKIX_HTTPCERTSTORECONTEXT_TYPE];
+
+ PKIX_ENTER(HTTPCERTSTORECONTEXT,
+ "pkix_pl_HttpCertStoreContext_RegisterSelf");
+
+ entry->description = "HttpCertStoreContext";
+ entry->typeObjectSize = sizeof(PKIX_PL_HttpCertStoreContext);
+ entry->destructor = pkix_pl_HttpCertStoreContext_Destroy;
+
+ PKIX_RETURN(HTTPCERTSTORECONTEXT);
+}
+
+
+/* --Private-Http-CertStore-Database-Functions----------------------- */
+
+typedef struct callbackContextStruct {
+ PKIX_List *pkixCertList;
+ PKIX_Error *error;
+ void *plContext;
+} callbackContext;
+
+
+/*
+ * FUNCTION: certCallback
+ * DESCRIPTION:
+ *
+ * This function processes the null-terminated array of SECItems produced by
+ * extracting the contents of a signedData message received in response to an
+ * HTTP cert query. Its address is supplied as a callback function to
+ * CERT_DecodeCertPackage; it is not expected to be called directly.
+ *
+ * Note that it does not conform to the libpkix API standard of returning
+ * a PKIX_Error*. It returns a SECStatus.
+ *
+ * PARAMETERS:
+ * "arg"
+ * The address of the callbackContext provided as a void* argument to
+ * CERT_DecodeCertPackage. Must be non-NULL.
+ * "secitemCerts"
+ * The address of the null-terminated array of SECItems. Must be non-NULL.
+ * "numcerts"
+ * The number of SECItems found in the signedData. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns SECSuccess if the function succeeds.
+ * Returns SECFailure if the function fails.
+ */
+static SECStatus
+certCallback(void *arg, SECItem **secitemCerts, int numcerts)
+{
+ callbackContext *cbContext;
+ PKIX_List *pkixCertList = NULL;
+ PKIX_Error *error = NULL;
+ void *plContext = NULL;
+ int itemNum = 0;
+
+ if ((arg == NULL) || (secitemCerts == NULL)) {
+ return (SECFailure);
+ }
+
+ cbContext = (callbackContext *)arg;
+ plContext = cbContext->plContext;
+ pkixCertList = cbContext->pkixCertList;
+
+ for (; itemNum < numcerts; itemNum++ ) {
+ error = pkix_pl_Cert_CreateToList(secitemCerts[itemNum],
+ pkixCertList, plContext);
+ if (error != NULL) {
+ if (error->errClass == PKIX_FATAL_ERROR) {
+ cbContext->error = error;
+ return SECFailure;
+ }
+ /* reuse "error" since we could not destruct the old *
+ * value */
+ error = PKIX_PL_Object_DecRef((PKIX_PL_Object *)error,
+ plContext);
+ if (error) {
+ /* Treat decref failure as a fatal error.
+ * In this case will leak error, but can not do
+ * anything about it. */
+ error->errClass = PKIX_FATAL_ERROR;
+ cbContext->error = error;
+ return SECFailure;
+ }
+ }
+ }
+
+ return SECSuccess;
+}
+
+
+typedef SECStatus (*pkix_DecodeCertsFunc)(char *certbuf, int certlen,
+ CERTImportCertificateFunc f, void *arg);
+
+
+struct pkix_DecodeFuncStr {
+ pkix_DecodeCertsFunc func; /* function pointer to the
+ * CERT_DecodeCertPackage function */
+ PRLibrary *smimeLib; /* Pointer to the smime shared lib*/
+ PRCallOnceType once;
+};
+
+static struct pkix_DecodeFuncStr pkix_decodeFunc;
+static const PRCallOnceType pkix_pristine;
+
+#define SMIME_LIB_NAME SHLIB_PREFIX"smime3."SHLIB_SUFFIX
+
+/*
+ * load the smime library and look up the SEC_ReadPKCS7Certs function.
+ * we do this so we don't have a circular depenency on the smime library,
+ * and also so we don't have to load the smime library in applications that
+ * don't use it.
+ */
+static PRStatus PR_CALLBACK pkix_getDecodeFunction(void)
+{
+ pkix_decodeFunc.smimeLib =
+ PR_LoadLibrary(SHLIB_PREFIX"smime3."SHLIB_SUFFIX);
+ if (pkix_decodeFunc.smimeLib == NULL) {
+ return PR_FAILURE;
+ }
+
+ pkix_decodeFunc.func = (pkix_DecodeCertsFunc) PR_FindFunctionSymbol(
+ pkix_decodeFunc.smimeLib, "CERT_DecodeCertPackage");
+ if (!pkix_decodeFunc.func) {
+ return PR_FAILURE;
+ }
+ return PR_SUCCESS;
+
+}
+
+/*
+ * clears our global state on shutdown.
+ */
+void
+pkix_pl_HttpCertStore_Shutdown(void *plContext)
+{
+ if (pkix_decodeFunc.smimeLib) {
+ PR_UnloadLibrary(pkix_decodeFunc.smimeLib);
+ pkix_decodeFunc.smimeLib = NULL;
+ }
+ /* the function pointer just need to be cleared, not freed */
+ pkix_decodeFunc.func = NULL;
+ pkix_decodeFunc.once = pkix_pristine;
+}
+
+/*
+ * This function is based on CERT_DecodeCertPackage from lib/pkcs7/certread.c
+ * read an old style ascii or binary certificate chain
+ */
+PKIX_Error *
+pkix_pl_HttpCertStore_DecodeCertPackage
+ (const char *certbuf,
+ int certlen,
+ CERTImportCertificateFunc f,
+ void *arg,
+ void *plContext)
+{
+
+ PRStatus status;
+ SECStatus rv;
+
+ PKIX_ENTER
+ (HTTPCERTSTORECONTEXT,
+ "pkix_pl_HttpCertStore_DecodeCertPackage");
+ PKIX_NULLCHECK_TWO(certbuf, f);
+
+ status = PR_CallOnce(&pkix_decodeFunc.once, pkix_getDecodeFunction);
+
+ if (status != PR_SUCCESS) {
+ PKIX_ERROR(PKIX_CANTLOADLIBSMIME);
+ }
+
+ /* paranoia, shouldn't happen if status == PR_SUCCESS); */
+ if (!pkix_decodeFunc.func) {
+ PKIX_ERROR(PKIX_CANTLOADLIBSMIME);
+ }
+
+ rv = (*pkix_decodeFunc.func)((char*)certbuf, certlen, f, arg);
+
+ if (rv != SECSuccess) {
+ PKIX_ERROR (PKIX_SECREADPKCS7CERTSFAILED);
+ }
+
+
+cleanup:
+
+ PKIX_RETURN(HTTPCERTSTORECONTEXT);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_HttpCertStore_ProcessCertResponse
+ * DESCRIPTION:
+ *
+ * This function verifies that the response code pointed to by "responseCode"
+ * and the content type pointed to by "responseContentType" are as expected,
+ * and then decodes the data pointed to by "responseData", of length
+ * "responseDataLen", into a List of Certs, possibly empty, which is returned
+ * at "pCertList".
+ *
+ * PARAMETERS:
+ * "responseCode"
+ * The value of the HTTP response code.
+ * "responseContentType"
+ * The address of the Content-type string. Must be non-NULL.
+ * "responseData"
+ * The address of the message data. Must be non-NULL.
+ * "responseDataLen"
+ * The length of the message data.
+ * "pCertList"
+ * The address of the List that is created. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HttpCertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_HttpCertStore_ProcessCertResponse(
+ PRUint16 responseCode,
+ const char *responseContentType,
+ const char *responseData,
+ PRUint32 responseDataLen,
+ PKIX_List **pCertList,
+ void *plContext)
+{
+ callbackContext cbContext;
+
+ PKIX_ENTER(HTTPCERTSTORECONTEXT,
+ "pkix_pl_HttpCertStore_ProcessCertResponse");
+
+ cbContext.error = NULL;
+ cbContext.plContext = plContext;
+ cbContext.pkixCertList = NULL;
+
+ PKIX_NULLCHECK_ONE(pCertList);
+
+ if (responseCode != 200) {
+ PKIX_ERROR(PKIX_BADHTTPRESPONSE);
+ }
+
+ /* check that response type is application/pkcs7-mime */
+ if (responseContentType == NULL) {
+ PKIX_ERROR(PKIX_NOCONTENTTYPEINHTTPRESPONSE);
+ }
+
+ if (responseData == NULL) {
+ PKIX_ERROR(PKIX_NORESPONSEDATAINHTTPRESPONSE);
+ }
+
+ PKIX_CHECK(
+ PKIX_List_Create(&cbContext.pkixCertList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ PKIX_CHECK_ONLY_FATAL(
+ pkix_pl_HttpCertStore_DecodeCertPackage(responseData,
+ responseDataLen,
+ certCallback,
+ &cbContext,
+ plContext),
+ PKIX_HTTPCERTSTOREDECODECERTPACKAGEFAILED);
+ if (cbContext.error) {
+ /* Aborting on a fatal error(See certCallback fn) */
+ pkixErrorResult = cbContext.error;
+ goto cleanup;
+ }
+
+ *pCertList = cbContext.pkixCertList;
+ cbContext.pkixCertList = NULL;
+
+cleanup:
+
+ PKIX_DECREF(cbContext.pkixCertList);
+
+ PKIX_RETURN(HTTPCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpCertStore_ProcessCrlResponse
+ * DESCRIPTION:
+ *
+ * This function verifies that the response code pointed to by "responseCode"
+ * and the content type pointed to by "responseContentType" are as expected,
+ * and then decodes the data pointed to by "responseData", of length
+ * "responseDataLen", into a List of Crls, possibly empty, which is returned
+ * at "pCrlList".
+ *
+ * PARAMETERS:
+ * "responseCode"
+ * The value of the HTTP response code.
+ * "responseContentType"
+ * The address of the Content-type string. Must be non-NULL.
+ * "responseData"
+ * The address of the message data. Must be non-NULL.
+ * "responseDataLen"
+ * The length of the message data.
+ * "pCrlList"
+ * The address of the List that is created. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HttpCertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_HttpCertStore_ProcessCrlResponse(
+ PRUint16 responseCode,
+ const char *responseContentType,
+ const char *responseData,
+ PRUint32 responseDataLen,
+ PKIX_List **pCrlList,
+ void *plContext)
+{
+ SECItem encodedResponse;
+ PRInt16 compareVal = 0;
+ PKIX_List *crls = NULL;
+ SECItem *derCrlCopy = NULL;
+ CERTSignedCrl *nssCrl = NULL;
+ PKIX_PL_CRL *crl = NULL;
+
+ PKIX_ENTER(HTTPCERTSTORECONTEXT,
+ "pkix_pl_HttpCertStore_ProcessCrlResponse");
+ PKIX_NULLCHECK_ONE(pCrlList);
+
+ if (responseCode != 200) {
+ PKIX_ERROR(PKIX_BADHTTPRESPONSE);
+ }
+
+ /* check that response type is application/pkix-crl */
+ if (responseContentType == NULL) {
+ PKIX_ERROR(PKIX_NOCONTENTTYPEINHTTPRESPONSE);
+ }
+
+ compareVal = PORT_Strcasecmp(responseContentType,
+ "application/pkix-crl");
+ if (compareVal != 0) {
+ PKIX_ERROR(PKIX_CONTENTTYPENOTPKIXCRL);
+ }
+ encodedResponse.type = siBuffer;
+ encodedResponse.data = (void*)responseData;
+ encodedResponse.len = responseDataLen;
+
+ derCrlCopy = SECITEM_DupItem(&encodedResponse);
+ if (!derCrlCopy) {
+ PKIX_ERROR(PKIX_ALLOCERROR);
+ }
+ /* crl will be based on derCrlCopy, but will not own the der. */
+ nssCrl =
+ CERT_DecodeDERCrlWithFlags(NULL, derCrlCopy, SEC_CRL_TYPE,
+ CRL_DECODE_DONT_COPY_DER |
+ CRL_DECODE_SKIP_ENTRIES);
+ if (!nssCrl) {
+ PKIX_ERROR(PKIX_FAILEDTODECODECRL);
+ }
+ /* pkix crls own the der. */
+ PKIX_CHECK(
+ pkix_pl_CRL_CreateWithSignedCRL(nssCrl, derCrlCopy, NULL,
+ &crl, plContext),
+ PKIX_CRLCREATEWITHSIGNEDCRLFAILED);
+ /* Left control over memory pointed by derCrlCopy and
+ * nssCrl to pkix crl. */
+ derCrlCopy = NULL;
+ nssCrl = NULL;
+ PKIX_CHECK(PKIX_List_Create(&crls, plContext),
+ PKIX_LISTCREATEFAILED);
+ PKIX_CHECK(PKIX_List_AppendItem
+ (crls, (PKIX_PL_Object *) crl, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ *pCrlList = crls;
+ crls = NULL;
+cleanup:
+ if (derCrlCopy) {
+ SECITEM_FreeItem(derCrlCopy, PR_TRUE);
+ }
+ if (nssCrl) {
+ SEC_DestroyCrl(nssCrl);
+ }
+ PKIX_DECREF(crl);
+ PKIX_DECREF(crls);
+
+ PKIX_RETURN(HTTPCERTSTORECONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpCertStore_CreateRequestSession
+ * DESCRIPTION:
+ *
+ * This function takes elements from the HttpCertStoreContext pointed to by
+ * "context" (path, client, and serverSession) and creates a RequestSession.
+ * See the HTTPClient API described in ocspt.h for further details.
+ *
+ * PARAMETERS:
+ * "context"
+ * The address of the HttpCertStoreContext. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HttpCertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_HttpCertStore_CreateRequestSession(
+ PKIX_PL_HttpCertStoreContext *context,
+ void *plContext)
+{
+ const SEC_HttpClientFcnV1 *hcv1 = NULL;
+ SECStatus rv = SECFailure;
+
+ PKIX_ENTER
+ (HTTPCERTSTORECONTEXT,
+ "pkix_pl_HttpCertStore_CreateRequestSession");
+ PKIX_NULLCHECK_TWO(context, context->serverSession);
+
+ if (context->client->version != 1) {
+ PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
+ }
+
+ hcv1 = &(context->client->fcnTable.ftable1);
+ if (context->requestSession != NULL) {
+ (*hcv1->freeFcn)(context->requestSession);
+ context->requestSession = 0;
+ }
+
+ rv = (*hcv1->createFcn)(context->serverSession, "http",
+ context->path, "GET",
+ PR_SecondsToInterval(
+ ((PKIX_PL_NssContext*)plContext)->timeoutSeconds),
+ &(context->requestSession));
+
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_HTTPSERVERERROR);
+ }
+cleanup:
+
+ PKIX_RETURN(HTTPCERTSTORECONTEXT);
+
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpCertStore_GetCert
+ * (see description of PKIX_CertStore_CertCallback in pkix_certstore.h)
+ */
+PKIX_Error *
+pkix_pl_HttpCertStore_GetCert(
+ PKIX_CertStore *store,
+ PKIX_CertSelector *selector,
+ PKIX_VerifyNode *verifyNode,
+ void **pNBIOContext,
+ PKIX_List **pCertList,
+ void *plContext)
+{
+ const SEC_HttpClientFcnV1 *hcv1 = NULL;
+ PKIX_PL_HttpCertStoreContext *context = NULL;
+ void *nbioContext = NULL;
+ SECStatus rv = SECFailure;
+ PRUint16 responseCode = 0;
+ const char *responseContentType = NULL;
+ const char *responseData = NULL;
+ PRUint32 responseDataLen = 0;
+ PKIX_List *certList = NULL;
+
+ PKIX_ENTER(HTTPCERTSTORECONTEXT, "pkix_pl_HttpCertStore_GetCert");
+ PKIX_NULLCHECK_THREE(store, selector, pCertList);
+
+ nbioContext = *pNBIOContext;
+ *pNBIOContext = NULL;
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
+ (store, (PKIX_PL_Object **)&context, plContext),
+ PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
+
+ if (context->client->version != 1) {
+ PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
+ }
+
+ hcv1 = &(context->client->fcnTable.ftable1);
+
+ PKIX_CHECK(pkix_pl_HttpCertStore_CreateRequestSession
+ (context, plContext),
+ PKIX_HTTPCERTSTORECREATEREQUESTSESSIONFAILED);
+
+ responseDataLen =
+ ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
+
+ rv = (*hcv1->trySendAndReceiveFcn)(context->requestSession,
+ (PRPollDesc **)&nbioContext,
+ &responseCode,
+ (const char **)&responseContentType,
+ NULL, /* &responseHeaders */
+ (const char **)&responseData,
+ &responseDataLen);
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_HTTPSERVERERROR);
+ }
+
+ if (nbioContext != 0) {
+ *pNBIOContext = nbioContext;
+ goto cleanup;
+ }
+
+ PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCertResponse
+ (responseCode,
+ responseContentType,
+ responseData,
+ responseDataLen,
+ &certList,
+ plContext),
+ PKIX_HTTPCERTSTOREPROCESSCERTRESPONSEFAILED);
+
+ *pCertList = certList;
+
+cleanup:
+ PKIX_DECREF(context);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpCertStore_GetCertContinue
+ * (see description of PKIX_CertStore_CertCallback in pkix_certstore.h)
+ */
+PKIX_Error *
+pkix_pl_HttpCertStore_GetCertContinue(
+ PKIX_CertStore *store,
+ PKIX_CertSelector *selector,
+ PKIX_VerifyNode *verifyNode,
+ void **pNBIOContext,
+ PKIX_List **pCertList,
+ void *plContext)
+{
+ const SEC_HttpClientFcnV1 *hcv1 = NULL;
+ PKIX_PL_HttpCertStoreContext *context = NULL;
+ void *nbioContext = NULL;
+ SECStatus rv = SECFailure;
+ PRUint16 responseCode = 0;
+ const char *responseContentType = NULL;
+ const char *responseData = NULL;
+ PRUint32 responseDataLen = 0;
+ PKIX_List *certList = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_HttpCertStore_GetCertContinue");
+ PKIX_NULLCHECK_THREE(store, selector, pCertList);
+
+ nbioContext = *pNBIOContext;
+ *pNBIOContext = NULL;
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
+ (store, (PKIX_PL_Object **)&context, plContext),
+ PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
+
+ if (context->client->version != 1) {
+ PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
+ }
+
+ hcv1 = &(context->client->fcnTable.ftable1);
+ PKIX_NULLCHECK_ONE(context->requestSession);
+
+ responseDataLen =
+ ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
+
+ rv = (*hcv1->trySendAndReceiveFcn)(context->requestSession,
+ (PRPollDesc **)&nbioContext,
+ &responseCode,
+ (const char **)&responseContentType,
+ NULL, /* &responseHeaders */
+ (const char **)&responseData,
+ &responseDataLen);
+
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_HTTPSERVERERROR);
+ }
+
+ if (nbioContext != 0) {
+ *pNBIOContext = nbioContext;
+ goto cleanup;
+ }
+
+ PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCertResponse
+ (responseCode,
+ responseContentType,
+ responseData,
+ responseDataLen,
+ &certList,
+ plContext),
+ PKIX_HTTPCERTSTOREPROCESSCERTRESPONSEFAILED);
+
+ *pCertList = certList;
+
+cleanup:
+ PKIX_DECREF(context);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpCertStore_GetCRL
+ * (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h)
+ */
+PKIX_Error *
+pkix_pl_HttpCertStore_GetCRL(
+ PKIX_CertStore *store,
+ PKIX_CRLSelector *selector,
+ void **pNBIOContext,
+ PKIX_List **pCrlList,
+ void *plContext)
+{
+
+ const SEC_HttpClientFcnV1 *hcv1 = NULL;
+ PKIX_PL_HttpCertStoreContext *context = NULL;
+ void *nbioContext = NULL;
+ SECStatus rv = SECFailure;
+ PRUint16 responseCode = 0;
+ const char *responseContentType = NULL;
+ const char *responseData = NULL;
+ PRUint32 responseDataLen = 0;
+ PKIX_List *crlList = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_HttpCertStore_GetCRL");
+ PKIX_NULLCHECK_THREE(store, selector, pCrlList);
+
+ nbioContext = *pNBIOContext;
+ *pNBIOContext = NULL;
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
+ (store, (PKIX_PL_Object **)&context, plContext),
+ PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
+
+ if (context->client->version != 1) {
+ PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
+ }
+
+ hcv1 = &(context->client->fcnTable.ftable1);
+ PKIX_CHECK(pkix_pl_HttpCertStore_CreateRequestSession
+ (context, plContext),
+ PKIX_HTTPCERTSTORECREATEREQUESTSESSIONFAILED);
+
+ responseDataLen =
+ ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
+
+ rv = (*hcv1->trySendAndReceiveFcn)(context->requestSession,
+ (PRPollDesc **)&nbioContext,
+ &responseCode,
+ (const char **)&responseContentType,
+ NULL, /* &responseHeaders */
+ (const char **)&responseData,
+ &responseDataLen);
+
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_HTTPSERVERERROR);
+ }
+
+ if (nbioContext != 0) {
+ *pNBIOContext = nbioContext;
+ goto cleanup;
+ }
+
+ PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCrlResponse
+ (responseCode,
+ responseContentType,
+ responseData,
+ responseDataLen,
+ &crlList,
+ plContext),
+ PKIX_HTTPCERTSTOREPROCESSCRLRESPONSEFAILED);
+
+ *pCrlList = crlList;
+
+cleanup:
+ PKIX_DECREF(context);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpCertStore_GetCRLContinue
+ * (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h)
+ */
+PKIX_Error *
+pkix_pl_HttpCertStore_GetCRLContinue(
+ PKIX_CertStore *store,
+ PKIX_CRLSelector *selector,
+ void **pNBIOContext,
+ PKIX_List **pCrlList,
+ void *plContext)
+{
+ const SEC_HttpClientFcnV1 *hcv1 = NULL;
+ PKIX_PL_HttpCertStoreContext *context = NULL;
+ void *nbioContext = NULL;
+ SECStatus rv = SECFailure;
+ PRUint16 responseCode = 0;
+ const char *responseContentType = NULL;
+ const char *responseData = NULL;
+ PRUint32 responseDataLen = 0;
+ PKIX_List *crlList = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_HttpCertStore_GetCRLContinue");
+ PKIX_NULLCHECK_FOUR(store, selector, pNBIOContext, pCrlList);
+
+ nbioContext = *pNBIOContext;
+ *pNBIOContext = NULL;
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
+ (store, (PKIX_PL_Object **)&context, plContext),
+ PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
+
+ if (context->client->version != 1) {
+ PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
+ }
+ hcv1 = &(context->client->fcnTable.ftable1);
+
+ PKIX_CHECK(pkix_pl_HttpCertStore_CreateRequestSession
+ (context, plContext),
+ PKIX_HTTPCERTSTORECREATEREQUESTSESSIONFAILED);
+
+ responseDataLen =
+ ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
+
+ rv = (*hcv1->trySendAndReceiveFcn)(context->requestSession,
+ (PRPollDesc **)&nbioContext,
+ &responseCode,
+ (const char **)&responseContentType,
+ NULL, /* &responseHeaders */
+ (const char **)&responseData,
+ &responseDataLen);
+
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_HTTPSERVERERROR);
+ }
+
+ if (nbioContext != 0) {
+ *pNBIOContext = nbioContext;
+ goto cleanup;
+ }
+
+ PKIX_CHECK(pkix_pl_HttpCertStore_ProcessCrlResponse
+ (responseCode,
+ responseContentType,
+ responseData,
+ responseDataLen,
+ &crlList,
+ plContext),
+ PKIX_HTTPCERTSTOREPROCESSCRLRESPONSEFAILED);
+
+ *pCrlList = crlList;
+
+cleanup:
+ PKIX_DECREF(context);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/* --Public-HttpCertStore-Functions----------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_HttpCertStore_CreateWithAsciiName
+ * DESCRIPTION:
+ *
+ * This function uses the HttpClient pointed to by "client" and the string
+ * (hostname:portnum/path, with portnum optional) pointed to by "locationAscii"
+ * to create an HttpCertStore connected to the desired location, storing the
+ * created CertStore at "pCertStore".
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the HttpClient. Must be non-NULL.
+ * "locationAscii"
+ * The address of the character string indicating the hostname, port, and
+ * path to be queried for Certs or Crls. Must be non-NULL.
+ * "pCertStore"
+ * The address in which the object is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HttpCertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_HttpCertStore_CreateWithAsciiName(
+ PKIX_PL_HttpClient *client,
+ char *locationAscii,
+ PKIX_CertStore **pCertStore,
+ void *plContext)
+{
+ const SEC_HttpClientFcn *clientFcn = NULL;
+ const SEC_HttpClientFcnV1 *hcv1 = NULL;
+ PKIX_PL_HttpCertStoreContext *httpCertStore = NULL;
+ PKIX_CertStore *certStore = NULL;
+ char *hostname = NULL;
+ char *path = NULL;
+ PRUint16 port = 0;
+ SECStatus rv = SECFailure;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_HttpCertStore_CreateWithAsciiName");
+ PKIX_NULLCHECK_TWO(locationAscii, pCertStore);
+
+ if (client == NULL) {
+ clientFcn = SEC_GetRegisteredHttpClient();
+ if (clientFcn == NULL) {
+ PKIX_ERROR(PKIX_NOREGISTEREDHTTPCLIENT);
+ }
+ } else {
+ clientFcn = (const SEC_HttpClientFcn *)client;
+ }
+
+ if (clientFcn->version != 1) {
+ PKIX_ERROR(PKIX_UNSUPPORTEDVERSIONOFHTTPCLIENT);
+ }
+
+ /* create a PKIX_PL_HttpCertStore object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_HTTPCERTSTORECONTEXT_TYPE,
+ sizeof (PKIX_PL_HttpCertStoreContext),
+ (PKIX_PL_Object **)&httpCertStore,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ /* Initialize fields */
+ httpCertStore->client = clientFcn; /* not a PKIX object! */
+
+ /* parse location -> hostname, port, path */
+ rv = CERT_ParseURL(locationAscii, &hostname, &port, &path);
+ if (rv == SECFailure || hostname == NULL || path == NULL) {
+ PKIX_ERROR(PKIX_URLPARSINGFAILED);
+ }
+
+ httpCertStore->path = path;
+ path = NULL;
+
+ hcv1 = &(clientFcn->fcnTable.ftable1);
+ rv = (*hcv1->createSessionFcn)(hostname, port,
+ &(httpCertStore->serverSession));
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_HTTPCLIENTCREATESESSIONFAILED);
+ }
+
+ httpCertStore->requestSession = NULL;
+
+ PKIX_CHECK(PKIX_CertStore_Create
+ (pkix_pl_HttpCertStore_GetCert,
+ pkix_pl_HttpCertStore_GetCRL,
+ pkix_pl_HttpCertStore_GetCertContinue,
+ pkix_pl_HttpCertStore_GetCRLContinue,
+ NULL, /* don't support trust */
+ NULL, /* can not store crls */
+ NULL, /* can not do revocation check */
+ (PKIX_PL_Object *)httpCertStore,
+ PKIX_TRUE, /* cache flag */
+ PKIX_FALSE, /* not local */
+ &certStore,
+ plContext),
+ PKIX_CERTSTORECREATEFAILED);
+
+ *pCertStore = certStore;
+ certStore = NULL;
+
+cleanup:
+ PKIX_DECREF(httpCertStore);
+ if (hostname) {
+ PORT_Free(hostname);
+ }
+ if (path) {
+ PORT_Free(path);
+ }
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: PKIX_PL_HttpCertStore_Create
+ * (see comments in pkix_samples_modules.h)
+ */
+PKIX_Error *
+PKIX_PL_HttpCertStore_Create(
+ PKIX_PL_HttpClient *client,
+ PKIX_PL_GeneralName *location,
+ PKIX_CertStore **pCertStore,
+ void *plContext)
+{
+ PKIX_PL_String *locationString = NULL;
+ char *locationAscii = NULL;
+ PKIX_UInt32 len = 0;
+
+ PKIX_ENTER(CERTSTORE, "PKIX_PL_HttpCertStore_Create");
+ PKIX_NULLCHECK_TWO(location, pCertStore);
+
+ PKIX_TOSTRING(location, &locationString, plContext,
+ PKIX_GENERALNAMETOSTRINGFAILED);
+
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ (locationString,
+ PKIX_ESCASCII,
+ (void **)&locationAscii,
+ &len,
+ plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+
+ PKIX_CHECK(pkix_pl_HttpCertStore_CreateWithAsciiName
+ (client, locationAscii, pCertStore, plContext),
+ PKIX_HTTPCERTSTORECREATEWITHASCIINAMEFAILED);
+
+cleanup:
+
+ PKIX_DECREF(locationString);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_HttpCertStore_FindSocketConnection
+ * DESCRIPTION:
+ *
+ PRIntervalTime timeout,
+ char *hostname,
+ PRUint16 portnum,
+ PRErrorCode *pStatus,
+ PKIX_PL_Socket **pSocket,
+
+ * This function checks for an existing socket, creating a new one if unable
+ * to find an existing one, for the host pointed to by "hostname" and the port
+ * pointed to by "portnum". If a new socket is created the PRIntervalTime in
+ * "timeout" will be used for the timeout value and a creation status is
+ * returned at "pStatus". The address of the socket is stored at "pSocket".
+ *
+ * PARAMETERS:
+ * "timeout"
+ * The PRIntervalTime of the timeout value.
+ * "hostname"
+ * The address of the string containing the hostname. Must be non-NULL.
+ * "portnum"
+ * The port number for the desired socket.
+ * "pStatus"
+ * The address at which the status is stored. Must be non-NULL.
+ * "pSocket"
+ * The address at which the socket is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HttpCertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_HttpCertStore_FindSocketConnection(
+ PRIntervalTime timeout,
+ char *hostname,
+ PRUint16 portnum,
+ PRErrorCode *pStatus,
+ PKIX_PL_Socket **pSocket,
+ void *plContext)
+{
+ PKIX_PL_String *formatString = NULL;
+ PKIX_PL_String *hostString = NULL;
+ PKIX_PL_String *domainString = NULL;
+ PKIX_PL_Socket *socket = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_HttpCertStore_FindSocketConnection");
+ PKIX_NULLCHECK_THREE(hostname, pStatus, pSocket);
+
+ *pStatus = 0;
+
+ /* create PKIX_PL_String from hostname and port */
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, "%s:%d", 0, &formatString, plContext),
+ PKIX_STRINGCREATEFAILED);
+
+#if 0
+hostname = "variation.red.iplanet.com";
+portnum = 2001;
+#endif
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, hostname, 0, &hostString, plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ PKIX_CHECK(PKIX_PL_Sprintf
+ (&domainString, plContext, formatString, hostString, portnum),
+ PKIX_STRINGCREATEFAILED);
+
+#ifdef PKIX_SOCKETCACHE
+ /* Is this domainName already in cache? */
+ PKIX_CHECK(PKIX_PL_HashTable_Lookup
+ (httpSocketCache,
+ (PKIX_PL_Object *)domainString,
+ (PKIX_PL_Object **)&socket,
+ plContext),
+ PKIX_HASHTABLELOOKUPFAILED);
+#endif
+ if (socket == NULL) {
+
+ /* No, create a connection (and cache it) */
+ PKIX_CHECK(pkix_pl_Socket_CreateByHostAndPort
+ (PKIX_FALSE, /* create a client, not a server */
+ timeout,
+ hostname,
+ portnum,
+ pStatus,
+ &socket,
+ plContext),
+ PKIX_SOCKETCREATEBYHOSTANDPORTFAILED);
+
+#ifdef PKIX_SOCKETCACHE
+ PKIX_CHECK(PKIX_PL_HashTable_Add
+ (httpSocketCache,
+ (PKIX_PL_Object *)domainString,
+ (PKIX_PL_Object *)socket,
+ plContext),
+ PKIX_HASHTABLEADDFAILED);
+#endif
+ }
+
+ *pSocket = socket;
+ socket = NULL;
+
+cleanup:
+
+ PKIX_DECREF(formatString);
+ PKIX_DECREF(hostString);
+ PKIX_DECREF(domainString);
+ PKIX_DECREF(socket);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.h
new file mode 100644
index 000000000..a03ea94d8
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpcertstore.h
@@ -0,0 +1,62 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_httpcertstore.h
+ *
+ * HTTPCertstore Object Type Definition
+ *
+ */
+
+#ifndef _PKIX_PL_HTTPCERTSTORE_H
+#define _PKIX_PL_HTTPCERTSTORE_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_HttpCertStoreContextStruct {
+ const SEC_HttpClientFcn *client;
+ SEC_HTTP_SERVER_SESSION serverSession;
+ SEC_HTTP_REQUEST_SESSION requestSession;
+ char *path;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_HttpCertStoreContext_RegisterSelf(void *plContext);
+
+void pkix_pl_HttpCertStore_Shutdown(void *plContext);
+
+PKIX_Error *
+pkix_pl_HttpCertStore_CreateWithAsciiName(
+ PKIX_PL_HttpClient *client,
+ char *locationAscii,
+ PKIX_CertStore **pCertStore,
+ void *plContext);
+
+PKIX_Error *
+pkix_HttpCertStore_FindSocketConnection(
+ PRIntervalTime timeout,
+ char *hostname,
+ PRUint16 portnum,
+ PRErrorCode *pStatus,
+ PKIX_PL_Socket **pSocket,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_HttpCertStore_ProcessCertResponse(
+ PRUint16 responseCode,
+ const char *responseContentType,
+ const char *responseData,
+ PRUint32 responseDataLen,
+ PKIX_List **pCertList,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_HTTPCERTSTORE_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c
new file mode 100644
index 000000000..9954f0ca6
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.c
@@ -0,0 +1,1654 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_httpdefaultclient.c
+ *
+ * HTTPDefaultClient Function Definitions
+ *
+ */
+
+#include "pkix_pl_httpdefaultclient.h"
+
+static void *plContext = NULL;
+
+/*
+ * The interface specification for an http client requires that it register
+ * a function table of type SEC_HttpClientFcn, which is defined as a union
+ * of tables, of which only version 1 is defined at present.
+ *
+ * Note: these functions violate the PKIX calling conventions, in that they
+ * return SECStatus rather than PKIX_Error*, and that they do not provide a
+ * plContext argument. They are implemented here as calls to PKIX functions,
+ * but the plContext value is circularly defined - a true kludge. Its value
+ * is saved at the time of the call to pkix_pl_HttpDefaultClient_Create for
+ * subsequent use, but since that initial call comes from the
+ * pkix_pl_HttpDefaultClient_CreateSessionFcn, it's not really getting saved.
+ */
+static SEC_HttpClientFcnV1 vtable = {
+ pkix_pl_HttpDefaultClient_CreateSessionFcn,
+ pkix_pl_HttpDefaultClient_KeepAliveSessionFcn,
+ pkix_pl_HttpDefaultClient_FreeSessionFcn,
+ pkix_pl_HttpDefaultClient_RequestCreateFcn,
+ pkix_pl_HttpDefaultClient_SetPostDataFcn,
+ pkix_pl_HttpDefaultClient_AddHeaderFcn,
+ pkix_pl_HttpDefaultClient_TrySendAndReceiveFcn,
+ pkix_pl_HttpDefaultClient_CancelFcn,
+ pkix_pl_HttpDefaultClient_FreeFcn
+};
+
+static SEC_HttpClientFcn httpClient;
+
+static const char *eohMarker = "\r\n\r\n";
+static const PKIX_UInt32 eohMarkLen = 4; /* strlen(eohMarker) */
+static const char *crlf = "\r\n";
+static const PKIX_UInt32 crlfLen = 2; /* strlen(crlf) */
+static const char *httpprotocol = "HTTP/";
+static const PKIX_UInt32 httpprotocolLen = 5; /* strlen(httpprotocol) */
+
+
+#define HTTP_UNKNOWN_CONTENT_LENGTH -1
+
+/* --Private-HttpDefaultClient-Functions------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_HdrCheckComplete
+ * DESCRIPTION:
+ *
+ * This function determines whether the headers in the current receive buffer
+ * in the HttpDefaultClient pointed to by "client" are complete. If so, the
+ * input data is checked for status code, content-type and content-length are
+ * extracted, and the client is set up to read the body of the response.
+ * Otherwise, the client is set up to continue reading header data.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the HttpDefaultClient object. Must be non-NULL.
+ * "bytesRead"
+ * The UInt32 number of bytes received in the latest read.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HttpDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_HdrCheckComplete(
+ PKIX_PL_HttpDefaultClient *client,
+ PKIX_UInt32 bytesRead,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_UInt32 alreadyScanned = 0;
+ PKIX_UInt32 comp = 0;
+ PKIX_UInt32 headerLength = 0;
+ PKIX_Int32 contentLength = HTTP_UNKNOWN_CONTENT_LENGTH;
+ char *eoh = NULL;
+ char *statusLineEnd = NULL;
+ char *space = NULL;
+ char *nextHeader = NULL;
+ const char *httpcode = NULL;
+ char *thisHeaderEnd = NULL;
+ char *value = NULL;
+ char *colon = NULL;
+ char *copy = NULL;
+ char *body = NULL;
+
+ PKIX_ENTER
+ (HTTPDEFAULTCLIENT,
+ "pkix_pl_HttpDefaultClient_HdrCheckComplete");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ *pKeepGoing = PKIX_FALSE;
+
+ /* Does buffer contain end-of-header marker? */
+
+ /* Copy number of scanned bytes into a variable. */
+ alreadyScanned = client->filledupBytes;
+ /*
+ * If this is the initial buffer, we have to scan from the beginning.
+ * If we scanned, failed to find eohMarker, and read some more, we
+ * only have to scan from where we left off.
+ */
+ if (alreadyScanned > eohMarkLen) {
+ /* Back up and restart scanning over a few bytes that were
+ * scanned before */
+ PKIX_UInt32 searchStartPos = alreadyScanned - eohMarkLen;
+ eoh = PL_strnstr(&(client->rcvBuf[searchStartPos]), eohMarker,
+ bytesRead + searchStartPos);
+ } else {
+ /* A search from the beginning of the buffer. */
+ eoh = PL_strnstr(client->rcvBuf, eohMarker, bytesRead);
+ }
+
+ client->filledupBytes += bytesRead;
+
+ if (eoh == NULL) { /* did we see end-of-header? */
+ /* No. Continue to read header data */
+ client->connectStatus = HTTP_RECV_HDR;
+ *pKeepGoing = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /* Yes. Calculate how many bytes in header (not counting eohMarker) */
+ headerLength = (eoh - client->rcvBuf);
+
+ /* allocate space to copy header (and for the NULL terminator) */
+ PKIX_CHECK(PKIX_PL_Malloc(headerLength + 1, (void **)&copy, plContext),
+ PKIX_MALLOCFAILED);
+
+ /* copy header data before we corrupt it (by storing NULLs) */
+ PORT_Memcpy(copy, client->rcvBuf, headerLength);
+ /* Store the NULL terminator */
+ copy[headerLength] = '\0';
+ client->rcvHeaders = copy;
+
+ /* Did caller want a pointer to header? */
+ if (client->rcv_http_headers != NULL) {
+ /* store pointer for caller */
+ *(client->rcv_http_headers) = copy;
+ }
+
+ /* Check that message status is okay. */
+ statusLineEnd = PL_strnstr(client->rcvBuf, crlf, client->capacity);
+ if (statusLineEnd == NULL) {
+ client->connectStatus = HTTP_ERROR;
+ PORT_SetError(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE);
+ goto cleanup;
+ }
+
+ *statusLineEnd = '\0';
+
+ space = strchr((const char *)client->rcvBuf, ' ');
+ if (space == NULL) {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+
+ comp = PORT_Strncasecmp((const char *)client->rcvBuf, httpprotocol,
+ httpprotocolLen);
+ if (comp != 0) {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+
+ httpcode = space + 1;
+ space = strchr(httpcode, ' ');
+ if (space == NULL) {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+ *space = '\0';
+
+ client->responseCode = atoi(httpcode);
+ if (client->responseCode != 200) {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+
+ /* Find the content-type and content-length */
+ nextHeader = statusLineEnd + crlfLen;
+ *eoh = '\0';
+ do {
+ thisHeaderEnd = NULL;
+ value = NULL;
+
+ colon = strchr(nextHeader, ':');
+ if (colon == NULL) {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+ *colon = '\0';
+ value = colon + 1;
+ if (*value != ' ') {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+ value++;
+ thisHeaderEnd = strstr(value, crlf);
+ if (thisHeaderEnd != NULL) {
+ *thisHeaderEnd = '\0';
+ }
+ comp = PORT_Strcasecmp(nextHeader, "content-type");
+ if (comp == 0) {
+ client->rcvContentType = PORT_Strdup(value);
+ } else {
+ comp = PORT_Strcasecmp(nextHeader, "content-length");
+ if (comp == 0) {
+ contentLength = atoi(value);
+ }
+ }
+ if (thisHeaderEnd != NULL) {
+ nextHeader = thisHeaderEnd + crlfLen;
+ } else {
+ nextHeader = NULL;
+ }
+ } while ((nextHeader != NULL) && (nextHeader < (eoh + crlfLen)));
+
+ /* Did caller provide a pointer to return content-type? */
+ if (client->rcv_http_content_type != NULL) {
+ *(client->rcv_http_content_type) = client->rcvContentType;
+ }
+
+ if (client->rcvContentType == NULL) {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+
+ /* How many bytes remain in current buffer, beyond the header? */
+ headerLength += eohMarkLen;
+ client->filledupBytes -= headerLength;
+
+ /*
+ * The headers have passed validation. Now figure out whether the
+ * message is within the caller's size limit (if one was specified).
+ */
+ switch (contentLength) {
+ case 0:
+ client->rcv_http_data_len = 0;
+ client->connectStatus = HTTP_COMPLETE;
+ *pKeepGoing = PKIX_FALSE;
+ break;
+
+ case HTTP_UNKNOWN_CONTENT_LENGTH:
+ /* Unknown contentLength indicator.Will be set by
+ * pkix_pl_HttpDefaultClient_RecvBody whey connection get closed */
+ client->rcv_http_data_len = HTTP_UNKNOWN_CONTENT_LENGTH;
+ contentLength = /* Try to reserve 4K+ buffer */
+ client->filledupBytes + HTTP_DATA_BUFSIZE;
+ if (client->maxResponseLen > 0 &&
+ contentLength > (PKIX_Int32)client->maxResponseLen) {
+ if (client->filledupBytes < client->maxResponseLen) {
+ contentLength = client->maxResponseLen;
+ } else {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+ }
+ /* set available number of bytes in the buffer */
+ client->capacity = contentLength;
+ client->connectStatus = HTTP_RECV_BODY;
+ *pKeepGoing = PKIX_TRUE;
+ break;
+
+ default:
+ client->rcv_http_data_len = contentLength;
+ if (client->maxResponseLen > 0 &&
+ (PKIX_Int32)client->maxResponseLen < contentLength) {
+ client->connectStatus = HTTP_ERROR;
+ goto cleanup;
+ }
+
+ /*
+ * Do we have all of the message body, or do we need to read some more?
+ */
+ if ((PKIX_Int32)client->filledupBytes < contentLength) {
+ client->connectStatus = HTTP_RECV_BODY;
+ *pKeepGoing = PKIX_TRUE;
+ } else {
+ client->connectStatus = HTTP_COMPLETE;
+ *pKeepGoing = PKIX_FALSE;
+ }
+ }
+
+ if (contentLength > 0) {
+ /* allocate a buffer of size contentLength for the content */
+ PKIX_CHECK(PKIX_PL_Malloc(contentLength, (void **)&body, plContext),
+ PKIX_MALLOCFAILED);
+
+ /* copy any remaining bytes in current buffer into new buffer */
+ if (client->filledupBytes > 0) {
+ PORT_Memcpy(body, &(client->rcvBuf[headerLength]),
+ client->filledupBytes);
+ }
+ }
+
+ PKIX_CHECK(PKIX_PL_Free(client->rcvBuf, plContext),
+ PKIX_FREEFAILED);
+ client->rcvBuf = body;
+
+cleanup:
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_HttpDefaultClient_Create
+ * DESCRIPTION:
+ *
+ * This function creates a new HttpDefaultClient, and stores the result at
+ * "pClient".
+ *
+ * The HttpClient API does not include a plContext argument in its
+ * function calls. Its value at the time of this Create call must be the
+ * same as when the client is invoked.
+ *
+ * PARAMETERS:
+ * "host"
+ * The name of the server with which we hope to exchange messages. Must
+ * be non-NULL.
+ * "portnum"
+ * The port number to be used for our connection to the server.
+ * "pClient"
+ * The address at which the created HttpDefaultClient is to be stored.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HttpDefaultClient Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_Create(
+ const char *host,
+ PRUint16 portnum,
+ PKIX_PL_HttpDefaultClient **pClient,
+ void *plContext)
+{
+ PKIX_PL_HttpDefaultClient *client = NULL;
+
+ PKIX_ENTER(HTTPDEFAULTCLIENT, "PKIX_PL_HttpDefaultClient_Create");
+ PKIX_NULLCHECK_TWO(pClient, host);
+
+ /* allocate an HttpDefaultClient */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_HTTPDEFAULTCLIENT_TYPE,
+ sizeof (PKIX_PL_HttpDefaultClient),
+ (PKIX_PL_Object **)&client,
+ plContext),
+ PKIX_COULDNOTCREATEHTTPDEFAULTCLIENTOBJECT);
+
+ /* Client timeout is overwritten in HttpDefaultClient_RequestCreate
+ * function. Default value will be ignored. */
+ client->timeout = 0;
+ client->connectStatus = HTTP_NOT_CONNECTED;
+ client->portnum = portnum;
+ client->bytesToWrite = 0;
+ client->send_http_data_len = 0;
+ client->rcv_http_data_len = 0;
+ client->capacity = 0;
+ client->filledupBytes = 0;
+ client->responseCode = 0;
+ client->maxResponseLen = 0;
+ client->GETLen = 0;
+ client->POSTLen = 0;
+ client->pRcv_http_data_len = NULL;
+ client->callbackList = NULL;
+ client->GETBuf = NULL;
+ client->POSTBuf = NULL;
+ client->rcvBuf = NULL;
+ /* "host" is a parsing result by CERT_GetURL function that adds
+ * "end of line" to the value. OK to dup the string. */
+ client->host = PORT_Strdup(host);
+ if (!client->host) {
+ PKIX_ERROR(PKIX_ALLOCERROR);
+ }
+ client->path = NULL;
+ client->rcvContentType = NULL;
+ client->rcvHeaders = NULL;
+ client->send_http_method = HTTP_POST_METHOD;
+ client->send_http_content_type = NULL;
+ client->send_http_data = NULL;
+ client->rcv_http_response_code = NULL;
+ client->rcv_http_content_type = NULL;
+ client->rcv_http_headers = NULL;
+ client->rcv_http_data = NULL;
+ client->socket = NULL;
+
+ /*
+ * The HttpClient API does not include a plContext argument in its
+ * function calls. Save it here.
+ */
+ client->plContext = plContext;
+
+ *pClient = client;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(client);
+ }
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_HttpDefaultClient *client = NULL;
+
+ PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_HTTPDEFAULTCLIENT_TYPE, plContext),
+ PKIX_OBJECTNOTANHTTPDEFAULTCLIENT);
+
+ client = (PKIX_PL_HttpDefaultClient *)object;
+
+ if (client->rcvHeaders) {
+ PKIX_PL_Free(client->rcvHeaders, plContext);
+ client->rcvHeaders = NULL;
+ }
+ if (client->rcvContentType) {
+ PORT_Free(client->rcvContentType);
+ client->rcvContentType = NULL;
+ }
+ if (client->GETBuf != NULL) {
+ PR_smprintf_free(client->GETBuf);
+ client->GETBuf = NULL;
+ }
+ if (client->POSTBuf != NULL) {
+ PKIX_PL_Free(client->POSTBuf, plContext);
+ client->POSTBuf = NULL;
+ }
+ if (client->rcvBuf != NULL) {
+ PKIX_PL_Free(client->rcvBuf, plContext);
+ client->rcvBuf = NULL;
+ }
+ if (client->host) {
+ PORT_Free(client->host);
+ client->host = NULL;
+ }
+ if (client->path) {
+ PORT_Free(client->path);
+ client->path = NULL;
+ }
+ PKIX_DECREF(client->socket);
+
+cleanup:
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_RegisterSelf
+ *
+ * DESCRIPTION:
+ * Registers PKIX_PL_HTTPDEFAULTCLIENT_TYPE and its related
+ * functions with systemClasses[]
+ *
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_HttpDefaultClient_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry *entry =
+ &systemClasses[PKIX_HTTPDEFAULTCLIENT_TYPE];
+
+ PKIX_ENTER(HTTPDEFAULTCLIENT,
+ "pkix_pl_HttpDefaultClient_RegisterSelf");
+
+ entry->description = "HttpDefaultClient";
+ entry->typeObjectSize = sizeof(PKIX_PL_HttpDefaultClient);
+ entry->destructor = pkix_pl_HttpDefaultClient_Destroy;
+
+ httpClient.version = 1;
+ httpClient.fcnTable.ftable1 = vtable;
+ (void)SEC_RegisterDefaultHttpClient(&httpClient);
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/* --Private-HttpDefaultClient-I/O-Functions---------------------------- */
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_ConnectContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether a socket Connect initiated earlier for the
+ * HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a flag
+ * indicating whether processing can continue without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the HttpDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HttpDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_ConnectContinue(
+ PKIX_PL_HttpDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PRErrorCode status;
+ PKIX_Boolean keepGoing = PKIX_FALSE;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER
+ (HTTPDEFAULTCLIENT,
+ "pkix_pl_HttpDefaultClient_ConnectContinue");
+ PKIX_NULLCHECK_ONE(client);
+
+ callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
+
+ PKIX_CHECK(callbackList->connectcontinueCallback
+ (client->socket, &status, plContext),
+ PKIX_SOCKETCONNECTCONTINUEFAILED);
+
+ if (status == 0) {
+ client->connectStatus = HTTP_CONNECTED;
+ keepGoing = PKIX_TRUE;
+ } else if (status != PR_IN_PROGRESS_ERROR) {
+ PKIX_ERROR(PKIX_UNEXPECTEDERRORINESTABLISHINGCONNECTION);
+ }
+
+ *pKeepGoing = keepGoing;
+
+cleanup:
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_Send
+ * DESCRIPTION:
+ *
+ * This function creates and sends HTTP-protocol headers and, if applicable,
+ * data, for the HttpDefaultClient "client", and stores in "pKeepGoing" a flag
+ * indicating whether processing can continue without further input, and at
+ * "pBytesTransferred" the number of bytes sent.
+ *
+ * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use
+ * and that transmission has not completed.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the HttpDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "pBytesTransferred"
+ * The address at which the number of bytes sent is stored. Must be
+ * non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HttpDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_Send(
+ PKIX_PL_HttpDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ PKIX_UInt32 *pBytesTransferred,
+ void *plContext)
+{
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_Int32 lenToWrite = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+ char *dataToWrite = NULL;
+
+ PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Send");
+ PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred);
+
+ *pKeepGoing = PKIX_FALSE;
+
+ /* Do we have anything waiting to go? */
+ if ((client->GETBuf) || (client->POSTBuf)) {
+
+ if (client->GETBuf) {
+ dataToWrite = client->GETBuf;
+ lenToWrite = client->GETLen;
+ } else {
+ dataToWrite = client->POSTBuf;
+ lenToWrite = client->POSTLen;
+ }
+
+ callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
+
+ PKIX_CHECK(callbackList->sendCallback
+ (client->socket,
+ dataToWrite,
+ lenToWrite,
+ &bytesWritten,
+ plContext),
+ PKIX_SOCKETSENDFAILED);
+
+ client->rcvBuf = NULL;
+ client->capacity = 0;
+ client->filledupBytes = 0;
+
+ /*
+ * If the send completed we can proceed to try for the
+ * response. If the send did not complete we will have
+ * to poll for completion later.
+ */
+ if (bytesWritten >= 0) {
+ client->connectStatus = HTTP_RECV_HDR;
+ *pKeepGoing = PKIX_TRUE;
+ } else {
+ client->connectStatus = HTTP_SEND_PENDING;
+ *pKeepGoing = PKIX_FALSE;
+ }
+
+ }
+
+ *pBytesTransferred = bytesWritten;
+
+cleanup:
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_SendContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether the sending of the HTTP message for the
+ * HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a
+ * flag indicating whether processing can continue without further input, and
+ * at "pBytesTransferred" the number of bytes sent.
+ *
+ * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use
+ * and that transmission has not completed.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the HttpDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "pBytesTransferred"
+ * The address at which the number of bytes sent is stored. Must be
+ * non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HttpDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_SendContinue(
+ PKIX_PL_HttpDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ PKIX_UInt32 *pBytesTransferred,
+ void *plContext)
+{
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_SendContinue");
+ PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred);
+
+ *pKeepGoing = PKIX_FALSE;
+
+ callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
+
+ PKIX_CHECK(callbackList->pollCallback
+ (client->socket, &bytesWritten, NULL, plContext),
+ PKIX_SOCKETPOLLFAILED);
+
+ /*
+ * If the send completed we can proceed to try for the
+ * response. If the send did not complete we will have
+ * continue to poll.
+ */
+ if (bytesWritten >= 0) {
+ client->connectStatus = HTTP_RECV_HDR;
+ *pKeepGoing = PKIX_TRUE;
+ }
+
+ *pBytesTransferred = bytesWritten;
+
+cleanup:
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_RecvHdr
+ * DESCRIPTION:
+ *
+ * This function receives HTTP headers for the HttpDefaultClient "client", and
+ * stores in "pKeepGoing" a flag indicating whether processing can continue
+ * without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the HttpDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HttpDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_RecvHdr(
+ PKIX_PL_HttpDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_UInt32 bytesToRead = 0;
+ PKIX_Int32 bytesRead = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RecvHdr");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ /*
+ * rcvbuf, capacity, and filledupBytes were
+ * initialized when we wrote the headers. We begin by reading
+ * HTTP_HEADER_BUFSIZE bytes, repeatedly increasing the buffersize and
+ * reading again if necessary, until we have read the end-of-header
+ * marker, "\r\n\r\n", or have reached our maximum.
+ */
+ client->capacity += HTTP_HEADER_BUFSIZE;
+ PKIX_CHECK(PKIX_PL_Realloc
+ (client->rcvBuf,
+ client->capacity,
+ (void **)&(client->rcvBuf),
+ plContext),
+ PKIX_REALLOCFAILED);
+
+ bytesToRead = client->capacity - client->filledupBytes;
+
+ callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
+
+ PKIX_CHECK(callbackList->recvCallback
+ (client->socket,
+ (void *)&(client->rcvBuf[client->filledupBytes]),
+ bytesToRead,
+ &bytesRead,
+ plContext),
+ PKIX_SOCKETRECVFAILED);
+
+ if (bytesRead > 0) {
+ /* client->filledupBytes will be adjusted by
+ * pkix_pl_HttpDefaultClient_HdrCheckComplete */
+ PKIX_CHECK(
+ pkix_pl_HttpDefaultClient_HdrCheckComplete(client, bytesRead,
+ pKeepGoing,
+ plContext),
+ PKIX_HTTPDEFAULTCLIENTHDRCHECKCOMPLETEFAILED);
+ } else {
+ client->connectStatus = HTTP_RECV_HDR_PENDING;
+ *pKeepGoing = PKIX_FALSE;
+ }
+
+cleanup:
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_RecvHdrContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether the receiving of the HTTP headers for the
+ * HttpDefaultClient "client" has completed, and stores in "pKeepGoing" a flag
+ * indicating whether processing can continue without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the HttpDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HttpDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_RecvHdrContinue(
+ PKIX_PL_HttpDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_Int32 bytesRead = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER
+ (HTTPDEFAULTCLIENT,
+ "pkix_pl_HttpDefaultClient_RecvHdrContinue");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
+
+ PKIX_CHECK(callbackList->pollCallback
+ (client->socket, NULL, &bytesRead, plContext),
+ PKIX_SOCKETPOLLFAILED);
+
+ if (bytesRead > 0) {
+ client->filledupBytes += bytesRead;
+
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_HdrCheckComplete
+ (client, bytesRead, pKeepGoing, plContext),
+ PKIX_HTTPDEFAULTCLIENTHDRCHECKCOMPLETEFAILED);
+
+ } else {
+
+ *pKeepGoing = PKIX_FALSE;
+
+ }
+
+cleanup:
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_RecvBody
+ * DESCRIPTION:
+ *
+ * This function processes the contents of the first buffer of a received
+ * HTTP-protocol message for the HttpDefaultClient "client", and stores in
+ * "pKeepGoing" a flag indicating whether processing can continue without
+ * further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the HttpDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HttpDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_RecvBody(
+ PKIX_PL_HttpDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_Int32 bytesRead = 0;
+ PKIX_Int32 bytesToRead = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RecvBody");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ callbackList = (PKIX_PL_Socket_Callback *)client->callbackList;
+
+ if (client->rcv_http_data_len != HTTP_UNKNOWN_CONTENT_LENGTH) {
+ bytesToRead = client->rcv_http_data_len -
+ client->filledupBytes;
+ } else {
+ /* Reading till the EOF. Context length is not known.*/
+ /* Check the buffer capacity: increase and
+ * reallocate if it is low. */
+ int freeBuffSize = client->capacity - client->filledupBytes;
+ if (freeBuffSize < HTTP_MIN_AVAILABLE_BUFFER_SIZE) {
+ /* New length will be consist of available(downloaded) bytes,
+ * plus remaining capacity, plus new expansion. */
+ int currBuffSize = client->capacity;
+ /* Try to increase the buffer by 4K */
+ unsigned int newLength = currBuffSize + HTTP_DATA_BUFSIZE;
+ if (client->maxResponseLen > 0 &&
+ newLength > client->maxResponseLen) {
+ newLength = client->maxResponseLen;
+ }
+ /* Check if we can grow the buffer and report an error if
+ * new size is not larger than the current size of the buffer.*/
+ if (newLength <= client->filledupBytes) {
+ client->rcv_http_data_len = client->filledupBytes;
+ client->connectStatus = HTTP_ERROR;
+ *pKeepGoing = PKIX_FALSE;
+ goto cleanup;
+ }
+ if (client->capacity < newLength) {
+ client->capacity = newLength;
+ PKIX_CHECK(
+ PKIX_PL_Realloc(client->rcvBuf, newLength,
+ (void**)&client->rcvBuf, plContext),
+ PKIX_REALLOCFAILED);
+ freeBuffSize = client->capacity -
+ client->filledupBytes;
+ }
+ }
+ bytesToRead = freeBuffSize;
+ }
+
+ /* Use poll callback if waiting on non-blocking IO */
+ if (client->connectStatus == HTTP_RECV_BODY_PENDING) {
+ PKIX_CHECK(callbackList->pollCallback
+ (client->socket, NULL, &bytesRead, plContext),
+ PKIX_SOCKETPOLLFAILED);
+ } else {
+ PKIX_CHECK(callbackList->recvCallback
+ (client->socket,
+ (void *)&(client->rcvBuf[client->filledupBytes]),
+ bytesToRead,
+ &bytesRead,
+ plContext),
+ PKIX_SOCKETRECVFAILED);
+ }
+
+ /* If bytesRead < 0, an error will be thrown by recvCallback, so
+ * need to handle >= 0 cases. */
+
+ /* bytesRead == 0 - IO was blocked. */
+ if (bytesRead == 0) {
+ client->connectStatus = HTTP_RECV_BODY_PENDING;
+ *pKeepGoing = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /* We got something. Did we get it all? */
+ client->filledupBytes += bytesRead;
+
+ /* continue if not enough bytes read or if complete size of
+ * transfer is unknown */
+ if (bytesToRead > bytesRead ||
+ client->rcv_http_data_len == HTTP_UNKNOWN_CONTENT_LENGTH) {
+ *pKeepGoing = PKIX_TRUE;
+ goto cleanup;
+ }
+ client->connectStatus = HTTP_COMPLETE;
+ *pKeepGoing = PKIX_FALSE;
+
+cleanup:
+ if (pkixErrorResult && pkixErrorResult->errCode ==
+ PKIX_PRRECVREPORTSNETWORKCONNECTIONCLOSED) {
+ if (client->rcv_http_data_len == HTTP_UNKNOWN_CONTENT_LENGTH) {
+ client->rcv_http_data_len = client->filledupBytes;
+ client->connectStatus = HTTP_COMPLETE;
+ *pKeepGoing = PKIX_FALSE;
+ PKIX_DECREF(pkixErrorResult);
+ } else {
+ client->connectStatus = HTTP_ERROR;
+ }
+ }
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_HttpDefaultClient_Dispatch
+ * DESCRIPTION:
+ *
+ * This function is the state machine dispatcher for the HttpDefaultClient
+ * pointed to by "client". Results are returned by changes to various fields
+ * in the context.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the HttpDefaultClient object. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HttpDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_HttpDefaultClient_Dispatch(
+ PKIX_PL_HttpDefaultClient *client,
+ void *plContext)
+{
+ PKIX_UInt32 bytesTransferred = 0;
+ PKIX_Boolean keepGoing = PKIX_TRUE;
+
+ PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Dispatch");
+ PKIX_NULLCHECK_ONE(client);
+
+ while (keepGoing) {
+ switch (client->connectStatus) {
+ case HTTP_CONNECT_PENDING:
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_ConnectContinue
+ (client, &keepGoing, plContext),
+ PKIX_HTTPDEFAULTCLIENTCONNECTCONTINUEFAILED);
+ break;
+ case HTTP_CONNECTED:
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_Send
+ (client, &keepGoing, &bytesTransferred, plContext),
+ PKIX_HTTPDEFAULTCLIENTSENDFAILED);
+ break;
+ case HTTP_SEND_PENDING:
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_SendContinue
+ (client, &keepGoing, &bytesTransferred, plContext),
+ PKIX_HTTPDEFAULTCLIENTSENDCONTINUEFAILED);
+ break;
+ case HTTP_RECV_HDR:
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvHdr
+ (client, &keepGoing, plContext),
+ PKIX_HTTPDEFAULTCLIENTRECVHDRFAILED);
+ break;
+ case HTTP_RECV_HDR_PENDING:
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvHdrContinue
+ (client, &keepGoing, plContext),
+ PKIX_HTTPDEFAULTCLIENTRECVHDRCONTINUEFAILED);
+ break;
+ case HTTP_RECV_BODY:
+ case HTTP_RECV_BODY_PENDING:
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_RecvBody
+ (client, &keepGoing, plContext),
+ PKIX_HTTPDEFAULTCLIENTRECVBODYFAILED);
+ break;
+ case HTTP_ERROR:
+ case HTTP_COMPLETE:
+ keepGoing = PKIX_FALSE;
+ break;
+ case HTTP_NOT_CONNECTED:
+ default:
+ PKIX_ERROR(PKIX_HTTPDEFAULTCLIENTINILLEGALSTATE);
+ }
+ }
+
+cleanup:
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+}
+
+/*
+ * --HttpClient vtable functions
+ * See comments in ocspt.h for the function (wrappers) that return SECStatus.
+ * The functions that return PKIX_Error* are the libpkix implementations.
+ */
+
+PKIX_Error *
+pkix_pl_HttpDefaultClient_CreateSession(
+ const char *host,
+ PRUint16 portnum,
+ SEC_HTTP_SERVER_SESSION *pSession,
+ void *plContext)
+{
+ PKIX_PL_HttpDefaultClient *client = NULL;
+
+ PKIX_ENTER
+ (HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_CreateSession");
+ PKIX_NULLCHECK_TWO(host, pSession);
+
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_Create
+ (host, portnum, &client, plContext),
+ PKIX_HTTPDEFAULTCLIENTCREATEFAILED);
+
+ *pSession = (SEC_HTTP_SERVER_SESSION)client;
+
+cleanup:
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+
+}
+
+PKIX_Error *
+pkix_pl_HttpDefaultClient_KeepAliveSession(
+ SEC_HTTP_SERVER_SESSION session,
+ PRPollDesc **pPollDesc,
+ void *plContext)
+{
+ PKIX_ENTER
+ (HTTPDEFAULTCLIENT,
+ "pkix_pl_HttpDefaultClient_KeepAliveSession");
+ PKIX_NULLCHECK_TWO(session, pPollDesc);
+
+ PKIX_CHECK(pkix_CheckType
+ ((PKIX_PL_Object *)session,
+ PKIX_HTTPDEFAULTCLIENT_TYPE,
+ plContext),
+ PKIX_SESSIONNOTANHTTPDEFAULTCLIENT);
+
+ /* XXX Not implemented */
+
+cleanup:
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+
+}
+
+PKIX_Error *
+pkix_pl_HttpDefaultClient_RequestCreate(
+ 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,
+ void *plContext)
+{
+ PKIX_PL_HttpDefaultClient *client = NULL;
+ PKIX_PL_Socket *socket = NULL;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+ PRFileDesc *fileDesc = NULL;
+ PRErrorCode status = 0;
+
+ PKIX_ENTER
+ (HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_RequestCreate");
+ PKIX_NULLCHECK_TWO(session, pRequest);
+
+ PKIX_CHECK(pkix_CheckType
+ ((PKIX_PL_Object *)session,
+ PKIX_HTTPDEFAULTCLIENT_TYPE,
+ plContext),
+ PKIX_SESSIONNOTANHTTPDEFAULTCLIENT);
+
+ client = (PKIX_PL_HttpDefaultClient *)session;
+
+ /* We only know how to do http */
+ if (PORT_Strncasecmp(http_protocol_variant, "http", 4) != 0) {
+ PKIX_ERROR(PKIX_UNRECOGNIZEDPROTOCOLREQUESTED);
+ }
+
+ if (PORT_Strncasecmp(http_request_method, "POST", 4) == 0) {
+ client->send_http_method = HTTP_POST_METHOD;
+ } else if (PORT_Strncasecmp(http_request_method, "GET", 3) == 0) {
+ client->send_http_method = HTTP_GET_METHOD;
+ } else {
+ /* We only know how to do POST and GET */
+ PKIX_ERROR(PKIX_UNRECOGNIZEDREQUESTMETHOD);
+ }
+
+ if (path_and_query_string) {
+ /* "path_and_query_string" is a parsing result by CERT_GetURL
+ * function that adds "end of line" to the value. OK to dup
+ * the string. */
+ client->path = PORT_Strdup(path_and_query_string);
+ if (!client->path) {
+ PKIX_ERROR(PKIX_ALLOCERROR);
+ }
+ }
+
+ client->timeout = timeout;
+
+#if 0
+ PKIX_CHECK(pkix_HttpCertStore_FindSocketConnection
+ (timeout,
+ "variation.red.iplanet.com", /* (char *)client->host, */
+ 2001, /* client->portnum, */
+ &status,
+ &socket,
+ plContext),
+ PKIX_HTTPCERTSTOREFINDSOCKETCONNECTIONFAILED);
+#else
+ PKIX_CHECK(pkix_HttpCertStore_FindSocketConnection
+ (timeout,
+ (char *)client->host,
+ client->portnum,
+ &status,
+ &socket,
+ plContext),
+ PKIX_HTTPCERTSTOREFINDSOCKETCONNECTIONFAILED);
+#endif
+
+ client->socket = socket;
+
+ PKIX_CHECK(pkix_pl_Socket_GetCallbackList
+ (socket, &callbackList, plContext),
+ PKIX_SOCKETGETCALLBACKLISTFAILED);
+
+ client->callbackList = (void *)callbackList;
+
+ PKIX_CHECK(pkix_pl_Socket_GetPRFileDesc
+ (socket, &fileDesc, plContext),
+ PKIX_SOCKETGETPRFILEDESCFAILED);
+
+ client->pollDesc.fd = fileDesc;
+ client->pollDesc.in_flags = 0;
+ client->pollDesc.out_flags = 0;
+
+ client->send_http_data = NULL;
+ client->send_http_data_len = 0;
+ client->send_http_content_type = NULL;
+
+ client->connectStatus =
+ ((status == 0) ? HTTP_CONNECTED : HTTP_CONNECT_PENDING);
+
+ /* Request object is the same object as Session object */
+ PKIX_INCREF(client);
+ *pRequest = client;
+
+cleanup:
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+
+}
+
+PKIX_Error *
+pkix_pl_HttpDefaultClient_SetPostData(
+ SEC_HTTP_REQUEST_SESSION request,
+ const char *http_data,
+ const PRUint32 http_data_len,
+ const char *http_content_type,
+ void *plContext)
+{
+ PKIX_PL_HttpDefaultClient *client = NULL;
+
+ PKIX_ENTER
+ (HTTPDEFAULTCLIENT,
+ "pkix_pl_HttpDefaultClient_SetPostData");
+ PKIX_NULLCHECK_ONE(request);
+
+ PKIX_CHECK(pkix_CheckType
+ ((PKIX_PL_Object *)request,
+ PKIX_HTTPDEFAULTCLIENT_TYPE,
+ plContext),
+ PKIX_REQUESTNOTANHTTPDEFAULTCLIENT);
+
+ client = (PKIX_PL_HttpDefaultClient *)request;
+
+ client->send_http_data = http_data;
+ client->send_http_data_len = http_data_len;
+ client->send_http_content_type = http_content_type;
+
+ /* Caller is allowed to give NULL or empty string for content_type */
+ if ((client->send_http_content_type == NULL) ||
+ (*(client->send_http_content_type) == '\0')) {
+ client->send_http_content_type = "application/ocsp-request";
+ }
+
+cleanup:
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+
+}
+
+PKIX_Error *
+pkix_pl_HttpDefaultClient_TrySendAndReceive(
+ SEC_HTTP_REQUEST_SESSION request,
+ 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,
+ PRPollDesc **pPollDesc,
+ SECStatus *pSECReturn,
+ void *plContext)
+{
+ PKIX_PL_HttpDefaultClient *client = NULL;
+ PKIX_UInt32 postLen = 0;
+ PRPollDesc *pollDesc = NULL;
+ char *sendbuf = NULL;
+ char portstr[16];
+
+ PKIX_ENTER
+ (HTTPDEFAULTCLIENT,
+ "pkix_pl_HttpDefaultClient_TrySendAndReceive");
+
+ PKIX_NULLCHECK_ONE(request);
+
+ PKIX_CHECK(pkix_CheckType
+ ((PKIX_PL_Object *)request,
+ PKIX_HTTPDEFAULTCLIENT_TYPE,
+ plContext),
+ PKIX_REQUESTNOTANHTTPDEFAULTCLIENT);
+
+ client = (PKIX_PL_HttpDefaultClient *)request;
+
+ if (!pPollDesc && client->timeout == 0) {
+ PKIX_ERROR_FATAL(PKIX_NULLARGUMENT);
+ }
+
+ if (pPollDesc) {
+ pollDesc = *pPollDesc;
+ }
+
+ /* if not continuing from an earlier WOULDBLOCK return... */
+ if (pollDesc == NULL) {
+
+ if (!((client->connectStatus == HTTP_CONNECTED) ||
+ (client->connectStatus == HTTP_CONNECT_PENDING))) {
+ PKIX_ERROR(PKIX_HTTPCLIENTININVALIDSTATE);
+ }
+
+ /* Did caller provide a value for response length? */
+ if (http_response_data_len != NULL) {
+ client->pRcv_http_data_len = http_response_data_len;
+ client->maxResponseLen = *http_response_data_len;
+ }
+
+ client->rcv_http_response_code = http_response_code;
+ client->rcv_http_content_type = http_response_content_type;
+ client->rcv_http_headers = http_response_headers;
+ client->rcv_http_data = http_response_data;
+
+ /* prepare the message */
+ portstr[0] = '\0';
+ if (client->portnum != 80) {
+ PR_snprintf(portstr, sizeof(portstr), ":%d",
+ client->portnum);
+ }
+
+ if (client->send_http_method == HTTP_POST_METHOD) {
+ sendbuf = PR_smprintf
+ ("POST %s HTTP/1.0\r\nHost: %s%s\r\n"
+ "Content-Type: %s\r\nContent-Length: %u\r\n\r\n",
+ client->path,
+ client->host,
+ portstr,
+ client->send_http_content_type,
+ client->send_http_data_len);
+ postLen = PORT_Strlen(sendbuf);
+
+ client->POSTLen = postLen + client->send_http_data_len;
+
+ /* allocate postBuffer big enough for header + data */
+ PKIX_CHECK(PKIX_PL_Malloc
+ (client->POSTLen,
+ (void **)&(client->POSTBuf),
+ plContext),
+ PKIX_MALLOCFAILED);
+
+ /* copy header into postBuffer */
+ PORT_Memcpy(client->POSTBuf, sendbuf, postLen);
+
+ /* append data after header */
+ PORT_Memcpy(&client->POSTBuf[postLen],
+ client->send_http_data,
+ client->send_http_data_len);
+
+ /* PR_smprintf_free original header buffer */
+ PR_smprintf_free(sendbuf);
+ sendbuf = NULL;
+
+ } else if (client->send_http_method == HTTP_GET_METHOD) {
+ client->GETBuf = PR_smprintf
+ ("GET %s HTTP/1.0\r\nHost: %s%s\r\n\r\n",
+ client->path,
+ client->host,
+ portstr);
+ client->GETLen = PORT_Strlen(client->GETBuf);
+ }
+
+ }
+
+ /* continue according to state */
+ PKIX_CHECK(pkix_pl_HttpDefaultClient_Dispatch(client, plContext),
+ PKIX_HTTPDEFAULTCLIENTDISPATCHFAILED);
+
+ switch (client->connectStatus) {
+ case HTTP_CONNECT_PENDING:
+ case HTTP_SEND_PENDING:
+ case HTTP_RECV_HDR_PENDING:
+ case HTTP_RECV_BODY_PENDING:
+ pollDesc = &(client->pollDesc);
+ *pSECReturn = SECWouldBlock;
+ break;
+ case HTTP_ERROR:
+ /* Did caller provide a pointer for length? */
+ if (client->pRcv_http_data_len != NULL) {
+ /* Was error "response too big?" */
+ if (client->rcv_http_data_len !=
+ HTTP_UNKNOWN_CONTENT_LENGTH &&
+ client->maxResponseLen >=
+ client->rcv_http_data_len) {
+ /* Yes, report needed space */
+ *(client->pRcv_http_data_len) =
+ client->rcv_http_data_len;
+ } else {
+ /* No, report problem other than size */
+ *(client->pRcv_http_data_len) = 0;
+ }
+ }
+
+ pollDesc = NULL;
+ *pSECReturn = SECFailure;
+ break;
+ case HTTP_COMPLETE:
+ *(client->rcv_http_response_code) =
+ client->responseCode;
+ if (client->pRcv_http_data_len != NULL) {
+ *http_response_data_len =
+ client->rcv_http_data_len;
+ }
+ if (client->rcv_http_data != NULL) {
+ *(client->rcv_http_data) = client->rcvBuf;
+ }
+ pollDesc = NULL;
+ *pSECReturn = SECSuccess;
+ break;
+ case HTTP_NOT_CONNECTED:
+ case HTTP_CONNECTED:
+ case HTTP_RECV_HDR:
+ case HTTP_RECV_BODY:
+ default:
+ pollDesc = NULL;
+ *pSECReturn = SECFailure;
+ PKIX_ERROR(PKIX_HTTPCLIENTININVALIDSTATE);
+ break;
+ }
+
+ if (pPollDesc) {
+ *pPollDesc = pollDesc;
+ }
+
+cleanup:
+ if (sendbuf) {
+ PR_smprintf_free(sendbuf);
+ }
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+
+}
+
+PKIX_Error *
+pkix_pl_HttpDefaultClient_Cancel(
+ SEC_HTTP_REQUEST_SESSION request,
+ void *plContext)
+{
+ PKIX_ENTER(HTTPDEFAULTCLIENT, "pkix_pl_HttpDefaultClient_Cancel");
+ PKIX_NULLCHECK_ONE(request);
+
+ PKIX_CHECK(pkix_CheckType
+ ((PKIX_PL_Object *)request,
+ PKIX_HTTPDEFAULTCLIENT_TYPE,
+ plContext),
+ PKIX_REQUESTNOTANHTTPDEFAULTCLIENT);
+
+ /* XXX Not implemented */
+
+cleanup:
+
+ PKIX_RETURN(HTTPDEFAULTCLIENT);
+
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_CreateSessionFcn(
+ const char *host,
+ PRUint16 portnum,
+ SEC_HTTP_SERVER_SESSION *pSession)
+{
+ PKIX_Error *err = pkix_pl_HttpDefaultClient_CreateSession
+ (host, portnum, pSession, plContext);
+
+ if (err) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_KeepAliveSessionFcn(
+ SEC_HTTP_SERVER_SESSION session,
+ PRPollDesc **pPollDesc)
+{
+ PKIX_Error *err = pkix_pl_HttpDefaultClient_KeepAliveSession
+ (session, pPollDesc, plContext);
+
+ if (err) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_FreeSessionFcn(
+ SEC_HTTP_SERVER_SESSION session)
+{
+ PKIX_Error *err =
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)(session), plContext);
+
+ if (err) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_RequestCreateFcn(
+ 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)
+{
+ PKIX_Error *err = pkix_pl_HttpDefaultClient_RequestCreate
+ (session,
+ http_protocol_variant,
+ path_and_query_string,
+ http_request_method,
+ timeout,
+ pRequest,
+ plContext);
+
+ if (err) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_SetPostDataFcn(
+ SEC_HTTP_REQUEST_SESSION request,
+ const char *http_data,
+ const PRUint32 http_data_len,
+ const char *http_content_type)
+{
+ PKIX_Error *err =
+ pkix_pl_HttpDefaultClient_SetPostData(request, http_data,
+ http_data_len,
+ http_content_type,
+ plContext);
+ if (err) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_AddHeaderFcn(
+ SEC_HTTP_REQUEST_SESSION request,
+ const char *http_header_name,
+ const char *http_header_value)
+{
+ /* Not supported */
+ return SECFailure;
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_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)
+{
+ SECStatus rv = SECFailure;
+
+ PKIX_Error *err = pkix_pl_HttpDefaultClient_TrySendAndReceive
+ (request,
+ http_response_code,
+ http_response_content_type,
+ http_response_headers,
+ http_response_data,
+ http_response_data_len,
+ pPollDesc,
+ &rv,
+ plContext);
+
+ if (err) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
+ return rv;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_CancelFcn(
+ SEC_HTTP_REQUEST_SESSION request)
+{
+ PKIX_Error *err = pkix_pl_HttpDefaultClient_Cancel(request, plContext);
+
+ if (err) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+SECStatus
+pkix_pl_HttpDefaultClient_FreeFcn(
+ SEC_HTTP_REQUEST_SESSION request)
+{
+ PKIX_Error *err =
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)(request), plContext);
+
+ if (err) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object *)err, plContext);
+ return SECFailure;
+ }
+ return SECSuccess;
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.h
new file mode 100644
index 000000000..91916a0ab
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_httpdefaultclient.h
@@ -0,0 +1,139 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_httpdefaultclient.h
+ *
+ * HTTPDefaultClient Object Type Definition
+ *
+ */
+
+#ifndef _PKIX_PL_HTTPDEFAULTCLIENT_H
+#define _PKIX_PL_HTTPDEFAULTCLIENT_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define HTTP_DATA_BUFSIZE 4096
+#define HTTP_HEADER_BUFSIZE 1024
+#define HTTP_MIN_AVAILABLE_BUFFER_SIZE 512
+
+typedef enum {
+ HTTP_NOT_CONNECTED,
+ HTTP_CONNECT_PENDING,
+ HTTP_CONNECTED,
+ HTTP_SEND_PENDING,
+ HTTP_RECV_HDR,
+ HTTP_RECV_HDR_PENDING,
+ HTTP_RECV_BODY,
+ HTTP_RECV_BODY_PENDING,
+ HTTP_COMPLETE,
+ HTTP_ERROR
+} HttpConnectStatus;
+
+typedef enum {
+ HTTP_POST_METHOD,
+ HTTP_GET_METHOD
+} HttpMethod;
+
+struct PKIX_PL_HttpDefaultClientStruct {
+ HttpConnectStatus connectStatus;
+ PRUint16 portnum;
+ PRIntervalTime timeout;
+ PKIX_UInt32 bytesToWrite;
+ PKIX_UInt32 send_http_data_len;
+ PKIX_UInt32 rcv_http_data_len;
+ PKIX_UInt32 capacity;
+ PKIX_UInt32 filledupBytes;
+ PKIX_UInt32 responseCode;
+ PKIX_UInt32 maxResponseLen;
+ PKIX_UInt32 GETLen;
+ PKIX_UInt32 POSTLen;
+ PRUint32 *pRcv_http_data_len;
+ PRPollDesc pollDesc;
+ void *callbackList; /* cast this to (PKIX_PL_Socket_Callback *) */
+ char *GETBuf;
+ char *POSTBuf;
+ char *rcvBuf;
+ char *host;
+ char *path;
+ char *rcvContentType;
+ void *rcvHeaders;
+ HttpMethod send_http_method;
+ const char *send_http_content_type;
+ const char *send_http_data;
+ PRUint16 *rcv_http_response_code;
+ const char **rcv_http_content_type;
+ const char **rcv_http_headers;
+ const char **rcv_http_data;
+ PKIX_PL_Socket *socket;
+ void *plContext;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_HttpDefaultClient_RegisterSelf(void *plContext);
+
+SECStatus
+pkix_pl_HttpDefaultClient_CreateSessionFcn(
+ const char *host,
+ PRUint16 portnum,
+ SEC_HTTP_SERVER_SESSION *pSession);
+
+SECStatus
+pkix_pl_HttpDefaultClient_KeepAliveSessionFcn(
+ SEC_HTTP_SERVER_SESSION session,
+ PRPollDesc **pPollDesc);
+
+SECStatus
+pkix_pl_HttpDefaultClient_FreeSessionFcn(
+ SEC_HTTP_SERVER_SESSION session);
+
+SECStatus
+pkix_pl_HttpDefaultClient_RequestCreateFcn(
+ 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);
+
+SECStatus
+pkix_pl_HttpDefaultClient_SetPostDataFcn(
+ SEC_HTTP_REQUEST_SESSION request,
+ const char *http_data,
+ const PRUint32 http_data_len,
+ const char *http_content_type);
+
+SECStatus
+pkix_pl_HttpDefaultClient_AddHeaderFcn(
+ SEC_HTTP_REQUEST_SESSION request,
+ const char *http_header_name,
+ const char *http_header_value);
+
+SECStatus
+pkix_pl_HttpDefaultClient_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);
+
+SECStatus
+pkix_pl_HttpDefaultClient_CancelFcn(
+ SEC_HTTP_REQUEST_SESSION request);
+
+SECStatus
+pkix_pl_HttpDefaultClient_FreeFcn(
+ SEC_HTTP_REQUEST_SESSION request);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_HTTPDEFAULTCLIENT_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.c
new file mode 100644
index 000000000..1b5d7577e
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.c
@@ -0,0 +1,1116 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_ldapcertstore.c
+ *
+ * LDAPCertStore Function Definitions
+ *
+ */
+
+/* We can't decode the length of a message without at least this many bytes */
+#define MINIMUM_MSG_LENGTH 5
+
+#include "pkix_pl_ldapcertstore.h"
+
+/* --Private-Ldap-CertStore-Database-Functions----------------------- */
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_DecodeCrossCertPair
+ * DESCRIPTION:
+ *
+ * This function decodes a DER-encoded CrossCertPair pointed to by
+ * "responseList" and extracts and decodes the Certificates in that pair,
+ * adding the resulting Certs, if the decoding was successful, to the List
+ * (possibly empty) pointed to by "certList". If none of the objects
+ * can be decoded into a Cert, the List is returned unchanged.
+ *
+ * PARAMETERS:
+ * "derCCPItem"
+ * The address of the SECItem containing the DER representation of the
+ * CrossCertPair. Must be non-NULL.
+ * "certList"
+ * The address of the List to which the decoded Certs are added. May be
+ * empty, but must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapCertStore_DecodeCrossCertPair(
+ SECItem *derCCPItem,
+ PKIX_List *certList,
+ void *plContext)
+{
+ LDAPCertPair certPair = {{ siBuffer, NULL, 0 }, { siBuffer, NULL, 0 }};
+ SECStatus rv = SECFailure;
+
+ PLArenaPool *tempArena = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_DecodeCrossCertPair");
+ PKIX_NULLCHECK_TWO(derCCPItem, certList);
+
+ tempArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!tempArena) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ rv = SEC_ASN1DecodeItem(tempArena, &certPair, PKIX_PL_LDAPCrossCertPairTemplate,
+ derCCPItem);
+ if (rv != SECSuccess) {
+ goto cleanup;
+ }
+
+ if (certPair.forward.data != NULL) {
+
+ PKIX_CHECK(
+ pkix_pl_Cert_CreateToList(&certPair.forward, certList,
+ plContext),
+ PKIX_CERTCREATETOLISTFAILED);
+ }
+
+ if (certPair.reverse.data != NULL) {
+
+ PKIX_CHECK(
+ pkix_pl_Cert_CreateToList(&certPair.reverse, certList,
+ plContext),
+ PKIX_CERTCREATETOLISTFAILED);
+ }
+
+cleanup:
+ if (tempArena) {
+ PORT_FreeArena(tempArena, PR_FALSE);
+ }
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_BuildCertList
+ * DESCRIPTION:
+ *
+ * This function takes a List of LdapResponse objects pointed to by
+ * "responseList" and extracts and decodes the Certificates in those responses,
+ * storing the List of those Certificates at "pCerts". If none of the objects
+ * can be decoded into a Cert, the returned List is empty.
+ *
+ * PARAMETERS:
+ * "responseList"
+ * The address of the List of LdapResponses. Must be non-NULL.
+ * "pCerts"
+ * The address at which the result is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapCertStore_BuildCertList(
+ PKIX_List *responseList,
+ PKIX_List **pCerts,
+ void *plContext)
+{
+ PKIX_UInt32 numResponses = 0;
+ PKIX_UInt32 respIx = 0;
+ LdapAttrMask attrBits = 0;
+ PKIX_PL_LdapResponse *response = NULL;
+ PKIX_List *certList = NULL;
+ LDAPMessage *message = NULL;
+ LDAPSearchResponseEntry *sre = NULL;
+ LDAPSearchResponseAttr **sreAttrArray = NULL;
+ LDAPSearchResponseAttr *sreAttr = NULL;
+ SECItem *attrType = NULL;
+ SECItem **attrVal = NULL;
+ SECItem *derCertItem = NULL;
+
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_BuildCertList");
+ PKIX_NULLCHECK_TWO(responseList, pCerts);
+
+ PKIX_CHECK(PKIX_List_Create(&certList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ /* extract certs from response */
+ PKIX_CHECK(PKIX_List_GetLength
+ (responseList, &numResponses, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ for (respIx = 0; respIx < numResponses; respIx++) {
+ PKIX_CHECK(PKIX_List_GetItem
+ (responseList,
+ respIx,
+ (PKIX_PL_Object **)&response,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapResponse_GetMessage
+ (response, &message, plContext),
+ PKIX_LDAPRESPONSEGETMESSAGEFAILED);
+
+ sre = &(message->protocolOp.op.searchResponseEntryMsg);
+ sreAttrArray = sre->attributes;
+
+ /* Get next element of null-terminated array */
+ sreAttr = *sreAttrArray++;
+ while (sreAttr != NULL) {
+ attrType = &(sreAttr->attrType);
+ PKIX_CHECK(pkix_pl_LdapRequest_AttrTypeToBit
+ (attrType, &attrBits, plContext),
+ PKIX_LDAPREQUESTATTRTYPETOBITFAILED);
+ /* Is this attrVal a Certificate? */
+ if (((LDAPATTR_CACERT | LDAPATTR_USERCERT) &
+ attrBits) == attrBits) {
+ attrVal = sreAttr->val;
+ derCertItem = *attrVal++;
+ while (derCertItem != 0) {
+ /* create a PKIX_PL_Cert from derCert */
+ PKIX_CHECK(pkix_pl_Cert_CreateToList
+ (derCertItem, certList, plContext),
+ PKIX_CERTCREATETOLISTFAILED);
+ derCertItem = *attrVal++;
+ }
+ } else if ((LDAPATTR_CROSSPAIRCERT & attrBits) == attrBits){
+ /* Is this attrVal a CrossPairCertificate? */
+ attrVal = sreAttr->val;
+ derCertItem = *attrVal++;
+ while (derCertItem != 0) {
+ /* create PKIX_PL_Certs from derCert */
+ PKIX_CHECK(pkix_pl_LdapCertStore_DecodeCrossCertPair
+ (derCertItem, certList, plContext),
+ PKIX_LDAPCERTSTOREDECODECROSSCERTPAIRFAILED);
+ derCertItem = *attrVal++;
+ }
+ }
+ sreAttr = *sreAttrArray++;
+ }
+ PKIX_DECREF(response);
+ }
+
+ *pCerts = certList;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(certList);
+ }
+
+ PKIX_DECREF(response);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_BuildCrlList
+ * DESCRIPTION:
+ *
+ * This function takes a List of LdapResponse objects pointed to by
+ * "responseList" and extracts and decodes the CRLs in those responses, storing
+ * the List of those CRLs at "pCrls". If none of the objects can be decoded
+ * into a CRL, the returned List is empty.
+ *
+ * PARAMETERS:
+ * "responseList"
+ * The address of the List of LdapResponses. Must be non-NULL.
+ * "pCrls"
+ * The address at which the result is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapCertStore_BuildCrlList(
+ PKIX_List *responseList,
+ PKIX_List **pCrls,
+ void *plContext)
+{
+ PKIX_UInt32 numResponses = 0;
+ PKIX_UInt32 respIx = 0;
+ LdapAttrMask attrBits = 0;
+ CERTSignedCrl *nssCrl = NULL;
+ PKIX_PL_LdapResponse *response = NULL;
+ PKIX_List *crlList = NULL;
+ PKIX_PL_CRL *crl = NULL;
+ LDAPMessage *message = NULL;
+ LDAPSearchResponseEntry *sre = NULL;
+ LDAPSearchResponseAttr **sreAttrArray = NULL;
+ LDAPSearchResponseAttr *sreAttr = NULL;
+ SECItem *attrType = NULL;
+ SECItem **attrVal = NULL;
+ SECItem *derCrlCopy = NULL;
+ SECItem *derCrlItem = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_BuildCrlList");
+ PKIX_NULLCHECK_TWO(responseList, pCrls);
+
+ PKIX_CHECK(PKIX_List_Create(&crlList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ /* extract crls from response */
+ PKIX_CHECK(PKIX_List_GetLength
+ (responseList, &numResponses, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ for (respIx = 0; respIx < numResponses; respIx++) {
+ PKIX_CHECK(PKIX_List_GetItem
+ (responseList,
+ respIx,
+ (PKIX_PL_Object **)&response,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapResponse_GetMessage
+ (response, &message, plContext),
+ PKIX_LDAPRESPONSEGETMESSAGEFAILED);
+
+ sre = &(message->protocolOp.op.searchResponseEntryMsg);
+ sreAttrArray = sre->attributes;
+
+ /* Get next element of null-terminated array */
+ sreAttr = *sreAttrArray++;
+ while (sreAttr != NULL) {
+ attrType = &(sreAttr->attrType);
+ PKIX_CHECK(pkix_pl_LdapRequest_AttrTypeToBit
+ (attrType, &attrBits, plContext),
+ PKIX_LDAPREQUESTATTRTYPETOBITFAILED);
+ /* Is this attrVal a Revocation List? */
+ if (((LDAPATTR_CERTREVLIST | LDAPATTR_AUTHREVLIST) &
+ attrBits) == attrBits) {
+ attrVal = sreAttr->val;
+ derCrlItem = *attrVal++;
+ while (derCrlItem != 0) {
+ /* create a PKIX_PL_Crl from derCrl */
+ derCrlCopy = SECITEM_DupItem(derCrlItem);
+ if (!derCrlCopy) {
+ PKIX_ERROR(PKIX_ALLOCERROR);
+ }
+ /* crl will be based on derCrlCopy, but wont
+ * own the der. */
+ nssCrl =
+ CERT_DecodeDERCrlWithFlags(NULL, derCrlCopy,
+ SEC_CRL_TYPE,
+ CRL_DECODE_DONT_COPY_DER |
+ CRL_DECODE_SKIP_ENTRIES);
+ if (!nssCrl) {
+ SECITEM_FreeItem(derCrlCopy, PKIX_TRUE);
+ continue;
+ }
+ /* pkix crl own the der. */
+ PKIX_CHECK(
+ pkix_pl_CRL_CreateWithSignedCRL(nssCrl,
+ derCrlCopy, NULL, &crl, plContext),
+ PKIX_CRLCREATEWITHSIGNEDCRLFAILED);
+ /* Left control over memory pointed by derCrlCopy and
+ * nssCrl to pkix crl. */
+ derCrlCopy = NULL;
+ nssCrl = NULL;
+ PKIX_CHECK(PKIX_List_AppendItem
+ (crlList, (PKIX_PL_Object *) crl, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ PKIX_DECREF(crl);
+ derCrlItem = *attrVal++;
+ }
+ /* Clean up after PKIX_CHECK_ONLY_FATAL */
+ pkixTempErrorReceived = PKIX_FALSE;
+ }
+ sreAttr = *sreAttrArray++;
+ }
+ PKIX_DECREF(response);
+ }
+
+ *pCrls = crlList;
+ crlList = NULL;
+cleanup:
+ if (derCrlCopy) {
+ SECITEM_FreeItem(derCrlCopy, PKIX_TRUE);
+ }
+ if (nssCrl) {
+ SEC_DestroyCrl(nssCrl);
+ }
+ PKIX_DECREF(crl);
+ PKIX_DECREF(crlList);
+ PKIX_DECREF(response);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_DestroyAVAList
+ * DESCRIPTION:
+ *
+ * This function frees the space allocated for the components of the
+ * equalFilters that make up the andFilter pointed to by "filter".
+ *
+ * PARAMETERS:
+ * "requestParams"
+ * The address of the andFilter whose components are to be freed. Must be
+ * non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapCertStore_DestroyAVAList(
+ LDAPNameComponent **nameComponents,
+ void *plContext)
+{
+ LDAPNameComponent **currentNC = NULL;
+ unsigned char *component = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_DestroyAVAList");
+ PKIX_NULLCHECK_ONE(nameComponents);
+
+ /* Set currentNC to point to first AVA pointer */
+ currentNC = nameComponents;
+
+ while ((*currentNC) != NULL) {
+ component = (*currentNC)->attrValue;
+ if (component != NULL) {
+ PORT_Free(component);
+ }
+ currentNC++;
+ }
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_MakeNameAVAList
+ * DESCRIPTION:
+ *
+ * This function allocates space from the arena pointed to by "arena" to
+ * construct a filter that will match components of the X500Name pointed to
+ * by "name", and stores the resulting filter at "pFilter".
+ *
+ * "name" is checked for commonName and organizationName components (cn=,
+ * and o=). The component strings are extracted using the family of
+ * CERT_Get* functions, and each must be freed with PORT_Free.
+ *
+ * It is not clear which components should be in a request, so, for now,
+ * we stop adding components after we have found one.
+ *
+ * PARAMETERS:
+ * "arena"
+ * The address of the PLArenaPool used in creating the filter. Must be
+ * non-NULL.
+ * "name"
+ * The address of the X500Name whose components define the desired
+ * matches. Must be non-NULL.
+ * "pList"
+ * The address at which the result is stored.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapCertStore_MakeNameAVAList(
+ PLArenaPool *arena,
+ PKIX_PL_X500Name *subjectName,
+ LDAPNameComponent ***pList,
+ void *plContext)
+{
+ LDAPNameComponent **setOfNameComponents;
+ LDAPNameComponent *currentNameComponent = NULL;
+ PKIX_UInt32 componentsPresent = 0;
+ void *v = NULL;
+ unsigned char *component = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_MakeNameAVAList");
+ PKIX_NULLCHECK_THREE(arena, subjectName, pList);
+
+ /* Increase this if additional components may be extracted */
+#define MAX_NUM_COMPONENTS 3
+
+ /* Space for (MAX_NUM_COMPONENTS + 1) pointers to LDAPNameComponents */
+ PKIX_PL_NSSCALLRV(CERTSTORE, v, PORT_ArenaZAlloc,
+ (arena, (MAX_NUM_COMPONENTS + 1)*sizeof(LDAPNameComponent *)));
+ setOfNameComponents = (LDAPNameComponent **)v;
+
+ /* Space for MAX_NUM_COMPONENTS LDAPNameComponents */
+ PKIX_PL_NSSCALLRV(CERTSTORE, v, PORT_ArenaZNewArray,
+ (arena, LDAPNameComponent, MAX_NUM_COMPONENTS));
+
+ currentNameComponent = (LDAPNameComponent *)v;
+
+ /* Try for commonName */
+ PKIX_CHECK(pkix_pl_X500Name_GetCommonName
+ (subjectName, &component, plContext),
+ PKIX_X500NAMEGETCOMMONNAMEFAILED);
+ if (component) {
+ setOfNameComponents[componentsPresent] = currentNameComponent;
+ currentNameComponent->attrType = (unsigned char *)"cn";
+ currentNameComponent->attrValue = component;
+ componentsPresent++;
+ currentNameComponent++;
+ }
+
+ /*
+ * The LDAP specification says we can send multiple name components
+ * in an "AND" filter, but the LDAP Servers don't seem to be able to
+ * handle such requests. So we'll quit after the cn component.
+ */
+#if 0
+ /* Try for orgName */
+ PKIX_CHECK(pkix_pl_X500Name_GetOrgName
+ (subjectName, &component, plContext),
+ PKIX_X500NAMEGETORGNAMEFAILED);
+ if (component) {
+ setOfNameComponents[componentsPresent] = currentNameComponent;
+ currentNameComponent->attrType = (unsigned char *)"o";
+ currentNameComponent->attrValue = component;
+ componentsPresent++;
+ currentNameComponent++;
+ }
+
+ /* Try for countryName */
+ PKIX_CHECK(pkix_pl_X500Name_GetCountryName
+ (subjectName, &component, plContext),
+ PKIX_X500NAMEGETCOUNTRYNAMEFAILED);
+ if (component) {
+ setOfNameComponents[componentsPresent] = currentNameComponent;
+ currentNameComponent->attrType = (unsigned char *)"c";
+ currentNameComponent->attrValue = component;
+ componentsPresent++;
+ currentNameComponent++;
+ }
+#endif
+
+ setOfNameComponents[componentsPresent] = NULL;
+
+ *pList = setOfNameComponents;
+
+cleanup:
+
+ PKIX_RETURN(CERTSTORE);
+
+}
+
+#if 0
+/*
+ * FUNCTION: pkix_pl_LdapCertstore_ConvertCertResponses
+ * DESCRIPTION:
+ *
+ * This function processes the List of LDAPResponses pointed to by "responses"
+ * into a List of resulting Certs, storing the result at "pCerts". If there
+ * are no responses converted successfully, a NULL may be stored.
+ *
+ * PARAMETERS:
+ * "responses"
+ * The LDAPResponses whose contents are to be converted. Must be non-NULL.
+ * "pCerts"
+ * Address at which the returned List is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in a non-fatal way
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapCertStore_ConvertCertResponses(
+ PKIX_List *responses,
+ PKIX_List **pCerts,
+ void *plContext)
+{
+ PKIX_List *unfiltered = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_ConvertCertResponses");
+ PKIX_NULLCHECK_TWO(responses, pCerts);
+
+ /*
+ * We have a List of LdapResponse objects that have to be
+ * turned into Certs.
+ */
+ PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList
+ (responses, &unfiltered, plContext),
+ PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED);
+
+ *pCerts = unfiltered;
+
+cleanup:
+
+ PKIX_RETURN(CERTSTORE);
+}
+#endif
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_GetCert
+ * (see description of PKIX_CertStore_CertCallback in pkix_certstore.h)
+ */
+PKIX_Error *
+pkix_pl_LdapCertStore_GetCert(
+ PKIX_CertStore *store,
+ PKIX_CertSelector *selector,
+ PKIX_VerifyNode *verifyNode,
+ void **pNBIOContext,
+ PKIX_List **pCertList,
+ void *plContext)
+{
+ PLArenaPool *requestArena = NULL;
+ LDAPRequestParams requestParams;
+ void *pollDesc = NULL;
+ PKIX_Int32 minPathLen = 0;
+ PKIX_Boolean cacheFlag = PKIX_FALSE;
+ PKIX_ComCertSelParams *params = NULL;
+ PKIX_PL_LdapCertStoreContext *lcs = NULL;
+ PKIX_List *responses = NULL;
+ PKIX_List *unfilteredCerts = NULL;
+ PKIX_List *filteredCerts = NULL;
+ PKIX_PL_X500Name *subjectName = 0;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_GetCert");
+ PKIX_NULLCHECK_THREE(store, selector, pCertList);
+
+ requestParams.baseObject = "c=US";
+ requestParams.scope = WHOLE_SUBTREE;
+ requestParams.derefAliases = NEVER_DEREF;
+ requestParams.sizeLimit = 0;
+ requestParams.timeLimit = 0;
+
+ /* Prepare elements for request filter */
+
+ /*
+ * Get a short-lived arena. We'll be done with this space once
+ * the request is encoded.
+ */
+ requestArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!requestArena) {
+ PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY);
+ }
+
+ PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams
+ (selector, &params, plContext),
+ PKIX_CERTSELECTORGETCOMCERTSELPARAMSFAILED);
+
+ /*
+ * If we have the subject name for the desired subject,
+ * ask the server for Certs with that subject.
+ */
+ PKIX_CHECK(PKIX_ComCertSelParams_GetSubject
+ (params, &subjectName, plContext),
+ PKIX_COMCERTSELPARAMSGETSUBJECTFAILED);
+
+ PKIX_CHECK(PKIX_ComCertSelParams_GetBasicConstraints
+ (params, &minPathLen, plContext),
+ PKIX_COMCERTSELPARAMSGETBASICCONSTRAINTSFAILED);
+
+ if (subjectName) {
+ PKIX_CHECK(pkix_pl_LdapCertStore_MakeNameAVAList
+ (requestArena,
+ subjectName,
+ &(requestParams.nc),
+ plContext),
+ PKIX_LDAPCERTSTOREMAKENAMEAVALISTFAILED);
+
+ if (*requestParams.nc == NULL) {
+ /*
+ * The subjectName may not include any components
+ * that we know how to encode. We do not return
+ * an error, because the caller did not necessarily
+ * do anything wrong, but we return an empty List.
+ */
+ PKIX_PL_NSSCALL(CERTSTORE, PORT_FreeArena,
+ (requestArena, PR_FALSE));
+
+ PKIX_CHECK(PKIX_List_Create(&filteredCerts, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_SetImmutable
+ (filteredCerts, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ *pNBIOContext = NULL;
+ *pCertList = filteredCerts;
+ filteredCerts = NULL;
+ goto cleanup;
+ }
+ } else {
+ PKIX_ERROR(PKIX_INSUFFICIENTCRITERIAFORCERTQUERY);
+ }
+
+ /* Prepare attribute field of request */
+
+ requestParams.attributes = 0;
+
+ if (minPathLen < 0) {
+ requestParams.attributes |= LDAPATTR_USERCERT;
+ }
+
+ if (minPathLen > -2) {
+ requestParams.attributes |=
+ LDAPATTR_CACERT | LDAPATTR_CROSSPAIRCERT;
+ }
+
+ /* All request fields are done */
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
+ (store, (PKIX_PL_Object **)&lcs, plContext),
+ PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
+
+ PKIX_CHECK(PKIX_PL_LdapClient_InitiateRequest
+ ((PKIX_PL_LdapClient *)lcs,
+ &requestParams,
+ &pollDesc,
+ &responses,
+ plContext),
+ PKIX_LDAPCLIENTINITIATEREQUESTFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapCertStore_DestroyAVAList
+ (requestParams.nc, plContext),
+ PKIX_LDAPCERTSTOREDESTROYAVALISTFAILED);
+
+ if (requestArena) {
+ PKIX_PL_NSSCALL(CERTSTORE, PORT_FreeArena,
+ (requestArena, PR_FALSE));
+ requestArena = NULL;
+ }
+
+ if (pollDesc != NULL) {
+ /* client is waiting for non-blocking I/O to complete */
+ *pNBIOContext = (void *)pollDesc;
+ *pCertList = NULL;
+ goto cleanup;
+ }
+ /* LdapClient has given us a response! */
+
+ if (responses) {
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreCacheFlag
+ (store, &cacheFlag, plContext),
+ PKIX_CERTSTOREGETCERTSTORECACHEFLAGFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList
+ (responses, &unfilteredCerts, plContext),
+ PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED);
+
+ PKIX_CHECK(pkix_CertSelector_Select
+ (selector, unfilteredCerts, &filteredCerts, plContext),
+ PKIX_CERTSELECTORSELECTFAILED);
+ }
+
+ *pNBIOContext = NULL;
+ *pCertList = filteredCerts;
+ filteredCerts = NULL;
+
+cleanup:
+
+ PKIX_DECREF(params);
+ PKIX_DECREF(subjectName);
+ PKIX_DECREF(responses);
+ PKIX_DECREF(unfilteredCerts);
+ PKIX_DECREF(filteredCerts);
+ PKIX_DECREF(lcs);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_GetCertContinue
+ * (see description of PKIX_CertStore_CertCallback in pkix_certstore.h)
+ */
+PKIX_Error *
+pkix_pl_LdapCertStore_GetCertContinue(
+ PKIX_CertStore *store,
+ PKIX_CertSelector *selector,
+ PKIX_VerifyNode *verifyNode,
+ void **pNBIOContext,
+ PKIX_List **pCertList,
+ void *plContext)
+{
+ PKIX_Boolean cacheFlag = PKIX_FALSE;
+ PKIX_PL_LdapCertStoreContext *lcs = NULL;
+ void *pollDesc = NULL;
+ PKIX_List *responses = NULL;
+ PKIX_List *unfilteredCerts = NULL;
+ PKIX_List *filteredCerts = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_GetCertContinue");
+ PKIX_NULLCHECK_THREE(store, selector, pCertList);
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
+ (store, (PKIX_PL_Object **)&lcs, plContext),
+ PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
+
+ PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest
+ ((PKIX_PL_LdapClient *)lcs, &pollDesc, &responses, plContext),
+ PKIX_LDAPCLIENTRESUMEREQUESTFAILED);
+
+ if (pollDesc != NULL) {
+ /* client is waiting for non-blocking I/O to complete */
+ *pNBIOContext = (void *)pollDesc;
+ *pCertList = NULL;
+ goto cleanup;
+ }
+ /* LdapClient has given us a response! */
+
+ if (responses) {
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreCacheFlag
+ (store, &cacheFlag, plContext),
+ PKIX_CERTSTOREGETCERTSTORECACHEFLAGFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapCertStore_BuildCertList
+ (responses, &unfilteredCerts, plContext),
+ PKIX_LDAPCERTSTOREBUILDCERTLISTFAILED);
+
+ PKIX_CHECK(pkix_CertSelector_Select
+ (selector, unfilteredCerts, &filteredCerts, plContext),
+ PKIX_CERTSELECTORSELECTFAILED);
+ }
+
+ *pNBIOContext = NULL;
+ *pCertList = filteredCerts;
+
+cleanup:
+
+ PKIX_DECREF(responses);
+ PKIX_DECREF(unfilteredCerts);
+ PKIX_DECREF(lcs);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_GetCRL
+ * (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h)
+ */
+PKIX_Error *
+pkix_pl_LdapCertStore_GetCRL(
+ PKIX_CertStore *store,
+ PKIX_CRLSelector *selector,
+ void **pNBIOContext,
+ PKIX_List **pCrlList,
+ void *plContext)
+{
+ LDAPRequestParams requestParams;
+ void *pollDesc = NULL;
+ PLArenaPool *requestArena = NULL;
+ PKIX_UInt32 numNames = 0;
+ PKIX_UInt32 thisName = 0;
+ PKIX_PL_CRL *candidate = NULL;
+ PKIX_List *responses = NULL;
+ PKIX_List *issuerNames = NULL;
+ PKIX_List *filteredCRLs = NULL;
+ PKIX_List *unfilteredCRLs = NULL;
+ PKIX_PL_X500Name *issuer = NULL;
+ PKIX_PL_LdapCertStoreContext *lcs = NULL;
+ PKIX_ComCRLSelParams *params = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_GetCRL");
+ PKIX_NULLCHECK_THREE(store, selector, pCrlList);
+
+ requestParams.baseObject = "c=US";
+ requestParams.scope = WHOLE_SUBTREE;
+ requestParams.derefAliases = NEVER_DEREF;
+ requestParams.sizeLimit = 0;
+ requestParams.timeLimit = 0;
+ requestParams.attributes = LDAPATTR_CERTREVLIST | LDAPATTR_AUTHREVLIST;
+ /* Prepare elements for request filter */
+
+ /* XXX Place CRLDP code here. Handle the case when */
+ /* RFC 5280. Paragraph: 4.2.1.13: */
+ /* If the distributionPoint field contains a directoryName, the entry */
+ /* for that directoryName contains the current CRL for the associated */
+ /* reasons and the CRL is issued by the associated cRLIssuer. The CRL */
+ /* may be stored in either the certificateRevocationList or */
+ /* authorityRevocationList attribute. The CRL is to be obtained by the */
+ /* application from whatever directory server is locally configured. */
+ /* The protocol the application uses to access the directory (e.g., DAP */
+ /* or LDAP) is a local matter. */
+
+
+
+ /*
+ * Get a short-lived arena. We'll be done with this space once
+ * the request is encoded.
+ */
+ PKIX_PL_NSSCALLRV
+ (CERTSTORE, requestArena, PORT_NewArena, (DER_DEFAULT_CHUNKSIZE));
+
+ if (!requestArena) {
+ PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY);
+ }
+
+ PKIX_CHECK(PKIX_CRLSelector_GetCommonCRLSelectorParams
+ (selector, &params, plContext),
+ PKIX_CRLSELECTORGETCOMCERTSELPARAMSFAILED);
+
+ PKIX_CHECK(PKIX_ComCRLSelParams_GetIssuerNames
+ (params, &issuerNames, plContext),
+ PKIX_COMCRLSELPARAMSGETISSUERNAMESFAILED);
+
+ /*
+ * The specification for PKIX_ComCRLSelParams_GetIssuerNames in
+ * pkix_crlsel.h says that if the criterion is not set we get a null
+ * pointer. If we get an empty List the criterion is impossible to
+ * meet ("must match at least one of the names in the List").
+ */
+ if (issuerNames) {
+
+ PKIX_CHECK(PKIX_List_GetLength
+ (issuerNames, &numNames, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ if (numNames > 0) {
+ for (thisName = 0; thisName < numNames; thisName++) {
+ PKIX_CHECK(PKIX_List_GetItem
+ (issuerNames,
+ thisName,
+ (PKIX_PL_Object **)&issuer,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK
+ (pkix_pl_LdapCertStore_MakeNameAVAList
+ (requestArena,
+ issuer,
+ &(requestParams.nc),
+ plContext),
+ PKIX_LDAPCERTSTOREMAKENAMEAVALISTFAILED);
+
+ PKIX_DECREF(issuer);
+
+ if (*requestParams.nc == NULL) {
+ /*
+ * The issuer may not include any
+ * components that we know how to
+ * encode. We do not return an error,
+ * because the caller did not
+ * necessarily do anything wrong, but
+ * we return an empty List.
+ */
+ PKIX_PL_NSSCALL
+ (CERTSTORE, PORT_FreeArena,
+ (requestArena, PR_FALSE));
+
+ PKIX_CHECK(PKIX_List_Create
+ (&filteredCRLs, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_SetImmutable
+ (filteredCRLs, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ *pNBIOContext = NULL;
+ *pCrlList = filteredCRLs;
+ goto cleanup;
+ }
+
+ /*
+ * LDAP Servers don't seem to be able to handle
+ * requests with more than more than one name.
+ */
+ break;
+ }
+ } else {
+ PKIX_ERROR(PKIX_IMPOSSIBLECRITERIONFORCRLQUERY);
+ }
+ } else {
+ PKIX_ERROR(PKIX_IMPOSSIBLECRITERIONFORCRLQUERY);
+ }
+
+ /* All request fields are done */
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
+ (store, (PKIX_PL_Object **)&lcs, plContext),
+ PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
+
+ PKIX_CHECK(PKIX_PL_LdapClient_InitiateRequest
+ ((PKIX_PL_LdapClient *)lcs,
+ &requestParams,
+ &pollDesc,
+ &responses,
+ plContext),
+ PKIX_LDAPCLIENTINITIATEREQUESTFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapCertStore_DestroyAVAList
+ (requestParams.nc, plContext),
+ PKIX_LDAPCERTSTOREDESTROYAVALISTFAILED);
+
+ if (requestArena) {
+ PKIX_PL_NSSCALL(CERTSTORE, PORT_FreeArena,
+ (requestArena, PR_FALSE));
+ }
+
+ if (pollDesc != NULL) {
+ /* client is waiting for non-blocking I/O to complete */
+ *pNBIOContext = (void *)pollDesc;
+ *pCrlList = NULL;
+ goto cleanup;
+ }
+ /* client has finished! */
+
+ if (responses) {
+
+ /*
+ * We have a List of LdapResponse objects that still have to be
+ * turned into Crls.
+ */
+ PKIX_CHECK(pkix_pl_LdapCertStore_BuildCrlList
+ (responses, &unfilteredCRLs, plContext),
+ PKIX_LDAPCERTSTOREBUILDCRLLISTFAILED);
+
+ PKIX_CHECK(pkix_CRLSelector_Select
+ (selector, unfilteredCRLs, &filteredCRLs, plContext),
+ PKIX_CRLSELECTORSELECTFAILED);
+
+ }
+
+ /* Don't throw away the list if one CRL was bad! */
+ pkixTempErrorReceived = PKIX_FALSE;
+
+ *pNBIOContext = NULL;
+ *pCrlList = filteredCRLs;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(filteredCRLs);
+ }
+
+ PKIX_DECREF(params);
+ PKIX_DECREF(issuerNames);
+ PKIX_DECREF(issuer);
+ PKIX_DECREF(candidate);
+ PKIX_DECREF(responses);
+ PKIX_DECREF(unfilteredCRLs);
+ PKIX_DECREF(lcs);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapCertStore_GetCRLContinue
+ * (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h)
+ */
+PKIX_Error *
+pkix_pl_LdapCertStore_GetCRLContinue(
+ PKIX_CertStore *store,
+ PKIX_CRLSelector *selector,
+ void **pNBIOContext,
+ PKIX_List **pCrlList,
+ void *plContext)
+{
+ void *nbio = NULL;
+ PKIX_PL_CRL *candidate = NULL;
+ PKIX_List *responses = NULL;
+ PKIX_PL_LdapCertStoreContext *lcs = NULL;
+ PKIX_List *filteredCRLs = NULL;
+ PKIX_List *unfilteredCRLs = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapCertStore_GetCRLContinue");
+ PKIX_NULLCHECK_FOUR(store, selector, pNBIOContext, pCrlList);
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreContext
+ (store, (PKIX_PL_Object **)&lcs, plContext),
+ PKIX_CERTSTOREGETCERTSTORECONTEXTFAILED);
+
+ PKIX_CHECK(PKIX_PL_LdapClient_ResumeRequest
+ ((PKIX_PL_LdapClient *)lcs, &nbio, &responses, plContext),
+ PKIX_LDAPCLIENTRESUMEREQUESTFAILED);
+
+ if (nbio != NULL) {
+ /* client is waiting for non-blocking I/O to complete */
+ *pNBIOContext = (void *)nbio;
+ *pCrlList = NULL;
+ goto cleanup;
+ }
+ /* client has finished! */
+
+ if (responses) {
+
+ /*
+ * We have a List of LdapResponse objects that still have to be
+ * turned into Crls.
+ */
+ PKIX_CHECK(pkix_pl_LdapCertStore_BuildCrlList
+ (responses, &unfilteredCRLs, plContext),
+ PKIX_LDAPCERTSTOREBUILDCRLLISTFAILED);
+
+ PKIX_CHECK(pkix_CRLSelector_Select
+ (selector, unfilteredCRLs, &filteredCRLs, plContext),
+ PKIX_CRLSELECTORSELECTFAILED);
+
+ PKIX_CHECK(PKIX_List_SetImmutable(filteredCRLs, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ }
+
+ /* Don't throw away the list if one CRL was bad! */
+ pkixTempErrorReceived = PKIX_FALSE;
+
+ *pCrlList = filteredCRLs;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(filteredCRLs);
+ }
+
+ PKIX_DECREF(candidate);
+ PKIX_DECREF(responses);
+ PKIX_DECREF(unfilteredCRLs);
+ PKIX_DECREF(lcs);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/* --Public-LdapCertStore-Functions----------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_LdapCertStore_Create
+ * (see comments in pkix_samples_modules.h)
+ */
+PKIX_Error *
+PKIX_PL_LdapCertStore_Create(
+ PKIX_PL_LdapClient *client,
+ PKIX_CertStore **pCertStore,
+ void *plContext)
+{
+ PKIX_CertStore *certStore = NULL;
+
+ PKIX_ENTER(CERTSTORE, "PKIX_PL_LdapCertStore_Create");
+ PKIX_NULLCHECK_TWO(client, pCertStore);
+
+ PKIX_CHECK(PKIX_CertStore_Create
+ (pkix_pl_LdapCertStore_GetCert,
+ pkix_pl_LdapCertStore_GetCRL,
+ pkix_pl_LdapCertStore_GetCertContinue,
+ pkix_pl_LdapCertStore_GetCRLContinue,
+ NULL, /* don't support trust */
+ NULL, /* can not store crls */
+ NULL, /* can not do revocation check */
+ (PKIX_PL_Object *)client,
+ PKIX_TRUE, /* cache flag */
+ PKIX_FALSE, /* not local */
+ &certStore,
+ plContext),
+ PKIX_CERTSTORECREATEFAILED);
+
+ *pCertStore = certStore;
+
+cleanup:
+
+ PKIX_RETURN(CERTSTORE);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.h
new file mode 100644
index 000000000..5bbe5385c
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapcertstore.h
@@ -0,0 +1,75 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_ldapcertstore.h
+ *
+ * LDAPCertstore Object Type Definition
+ *
+ */
+
+#ifndef _PKIX_PL_LDAPCERTSTORE_H
+#define _PKIX_PL_LDAPCERTSTORE_H
+
+#include "pkix_pl_ldapt.h"
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * At the time of this version, there are unresolved questions about the LDAP
+ * protocol. Although RFC1777 describes a BIND and UNBIND message, it is not
+ * clear whether they are appropriate to this application. We have tested only
+ * using servers that do not expect authentication, and that reject BIND
+ * messages. It is not clear what values might be appropriate for the bindname
+ * and authentication fields, which are currently implemented as char strings
+ * supplied by the caller. (If this changes, the API and possibly the templates
+ * will have to change.) Therefore the CertStore_Create API contains a BindAPI
+ * structure, a union, which will have to be revised and extended when this
+ * area of the protocol is better understood.
+ *
+ * It is further assumed that a given LdapCertStore will connect only to a
+ * single server, and that the creation of the socket will initiate the
+ * CONNECT. Therefore the LdapCertStore handles only the case of continuing
+ * the connection, if nonblocking I/O is being used.
+ */
+
+typedef enum {
+ LDAP_CONNECT_PENDING,
+ LDAP_CONNECTED,
+ LDAP_BIND_PENDING,
+ LDAP_BIND_RESPONSE,
+ LDAP_BIND_RESPONSE_PENDING,
+ LDAP_BOUND,
+ LDAP_SEND_PENDING,
+ LDAP_RECV,
+ LDAP_RECV_PENDING,
+ LDAP_RECV_INITIAL,
+ LDAP_RECV_NONINITIAL,
+ LDAP_ABANDON_PENDING
+} LDAPConnectStatus;
+
+#define LDAP_CACHEBUCKETS 128
+#define RCVBUFSIZE 512
+
+struct PKIX_PL_LdapCertStoreContext {
+ PKIX_PL_LdapClient *client;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_LdapCertStoreContext_RegisterSelf(void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapCertStore_BuildCertList(
+ PKIX_List *responseList,
+ PKIX_List **pCerts,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_LDAPCERTSTORE_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.c
new file mode 100644
index 000000000..3dc06be9a
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.c
@@ -0,0 +1,2493 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_ldapdefaultclient.c
+ *
+ * LDAPDefaultClient Function Definitions
+ *
+ */
+
+/* We can't decode the length of a message without at least this many bytes */
+#define MINIMUM_MSG_LENGTH 5
+
+#include "pkix_pl_ldapdefaultclient.h"
+
+/* --Private-LdapDefaultClient-Message-Building-Functions---------------- */
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_MakeBind
+ * DESCRIPTION:
+ *
+ * This function creates and encodes a Bind message, using the arena pointed
+ * to by "arena", the version number contained in "versionData", the
+ * LDAPBindAPI pointed to by "bindAPI", and the messageID contained in
+ * "msgNum", and stores a pointer to the encoded string at "pBindMsg".
+ *
+ * See pkix_pl_ldaptemplates.c for the ASN.1 description of a Bind message.
+ *
+ * This code is not used if the DefaultClient was created with a NULL pointer
+ * supplied for the LDAPBindAPI structure. (Bind and Unbind do not seem to be
+ * expected for anonymous Search requests.)
+ *
+ * PARAMETERS:
+ * "arena"
+ * The address of the PLArenaPool used in encoding the message. Must be
+ * non-NULL.
+ * "versionData"
+ * The Int32 containing the version number to be encoded in the Bind
+ * message.
+ * "bindAPI"
+ * The address of the LDAPBindAPI to be encoded in the Bind message. Must
+ * be non-NULL.
+ * "msgNum"
+ * The Int32 containing the MessageID to be encoded in the Bind message.
+ * "pBindMsg"
+ * The address at which the encoded Bind message will be stored. Must be
+ * non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_MakeBind(
+ PLArenaPool *arena,
+ PKIX_Int32 versionData,
+ LDAPBindAPI *bindAPI,
+ PKIX_UInt32 msgNum,
+ SECItem **pBindMsg,
+ void *plContext)
+{
+ LDAPMessage msg;
+ char version = '\0';
+ SECItem *encoded = NULL;
+ PKIX_UInt32 len = 0;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_MakeBind");
+ PKIX_NULLCHECK_TWO(arena, pBindMsg);
+
+ PKIX_PL_NSSCALL(LDAPDEFAULTCLIENT, PORT_Memset,
+ (&msg, 0, sizeof (LDAPMessage)));
+
+ version = (char)versionData;
+
+ msg.messageID.type = siUnsignedInteger;
+ msg.messageID.data = (void*)&msgNum;
+ msg.messageID.len = sizeof (msgNum);
+
+ msg.protocolOp.selector = LDAP_BIND_TYPE;
+
+ msg.protocolOp.op.bindMsg.version.type = siUnsignedInteger;
+ msg.protocolOp.op.bindMsg.version.data = (void *)&version;
+ msg.protocolOp.op.bindMsg.version.len = sizeof (char);
+
+ /*
+ * XXX At present we only know how to handle anonymous requests (no
+ * authentication), and we are guessing how to do simple authentication.
+ * This section will need to be revised and extended when other
+ * authentication is needed.
+ */
+ if (bindAPI->selector == SIMPLE_AUTH) {
+ msg.protocolOp.op.bindMsg.bindName.type = siAsciiString;
+ msg.protocolOp.op.bindMsg.bindName.data =
+ (void *)bindAPI->chooser.simple.bindName;
+ len = PL_strlen(bindAPI->chooser.simple.bindName);
+ msg.protocolOp.op.bindMsg.bindName.len = len;
+
+ msg.protocolOp.op.bindMsg.authentication.type = siAsciiString;
+ msg.protocolOp.op.bindMsg.authentication.data =
+ (void *)bindAPI->chooser.simple.authentication;
+ len = PL_strlen(bindAPI->chooser.simple.authentication);
+ msg.protocolOp.op.bindMsg.authentication.len = len;
+ }
+
+ PKIX_PL_NSSCALLRV(LDAPDEFAULTCLIENT, encoded, SEC_ASN1EncodeItem,
+ (arena, NULL, (void *)&msg, PKIX_PL_LDAPMessageTemplate));
+ if (!encoded) {
+ PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED);
+ }
+
+ *pBindMsg = encoded;
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_MakeUnbind
+ * DESCRIPTION:
+ *
+ * This function creates and encodes a Unbind message, using the arena pointed
+ * to by "arena" and the messageID contained in "msgNum", and stores a pointer
+ * to the encoded string at "pUnbindMsg".
+ *
+ * See pkix_pl_ldaptemplates.c for the ASN.1 description of an Unbind message.
+ *
+ * This code is not used if the DefaultClient was created with a NULL pointer
+ * supplied for the LDAPBindAPI structure. (Bind and Unbind do not seem to be
+ * expected for anonymous Search requests.)
+ *
+ * PARAMETERS:
+ * "arena"
+ * The address of the PLArenaPool used in encoding the message. Must be
+ * non-NULL.
+ * "msgNum"
+ * The Int32 containing the MessageID to be encoded in the Unbind message.
+ * "pUnbindMsg"
+ * The address at which the encoded Unbind message will be stored. Must
+ * be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_MakeUnbind(
+ PLArenaPool *arena,
+ PKIX_UInt32 msgNum,
+ SECItem **pUnbindMsg,
+ void *plContext)
+{
+ LDAPMessage msg;
+ SECItem *encoded = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_MakeUnbind");
+ PKIX_NULLCHECK_TWO(arena, pUnbindMsg);
+
+ PKIX_PL_NSSCALL(LDAPDEFAULTCLIENT, PORT_Memset,
+ (&msg, 0, sizeof (LDAPMessage)));
+
+ msg.messageID.type = siUnsignedInteger;
+ msg.messageID.data = (void*)&msgNum;
+ msg.messageID.len = sizeof (msgNum);
+
+ msg.protocolOp.selector = LDAP_UNBIND_TYPE;
+
+ msg.protocolOp.op.unbindMsg.dummy.type = siBuffer;
+ msg.protocolOp.op.unbindMsg.dummy.data = NULL;
+ msg.protocolOp.op.unbindMsg.dummy.len = 0;
+
+ PKIX_PL_NSSCALLRV(LDAPDEFAULTCLIENT, encoded, SEC_ASN1EncodeItem,
+ (arena, NULL, (void *)&msg, PKIX_PL_LDAPMessageTemplate));
+ if (!encoded) {
+ PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED);
+ }
+
+ *pUnbindMsg = encoded;
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_MakeAbandon
+ * DESCRIPTION:
+ *
+ * This function creates and encodes a Abandon message, using the arena pointed
+ * to by "arena" and the messageID contained in "msgNum", and stores a pointer
+ * to the encoded string at "pAbandonMsg".
+ *
+ * See pkix_pl_ldaptemplates.c for the ASN.1 description of an Abandon message.
+ *
+ * PARAMETERS:
+ * "arena"
+ * The address of the PLArenaPool used in encoding the message. Must be
+ * non-NULL.
+ * "msgNum"
+ * The Int32 containing the MessageID to be encoded in the Abandon message.
+ * "pAbandonMsg"
+ * The address at which the encoded Abandon message will be stored. Must
+ * be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_MakeAbandon(
+ PLArenaPool *arena,
+ PKIX_UInt32 msgNum,
+ SECItem **pAbandonMsg,
+ void *plContext)
+{
+ LDAPMessage msg;
+ SECItem *encoded = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_MakeAbandon");
+ PKIX_NULLCHECK_TWO(arena, pAbandonMsg);
+
+ PKIX_PL_NSSCALL(LDAPDEFAULTCLIENT, PORT_Memset,
+ (&msg, 0, sizeof (LDAPMessage)));
+
+ msg.messageID.type = siUnsignedInteger;
+ msg.messageID.data = (void*)&msgNum;
+ msg.messageID.len = sizeof (msgNum);
+
+ msg.protocolOp.selector = LDAP_ABANDONREQUEST_TYPE;
+
+ msg.protocolOp.op.abandonRequestMsg.messageID.type = siBuffer;
+ msg.protocolOp.op.abandonRequestMsg.messageID.data = (void*)&msgNum;
+ msg.protocolOp.op.abandonRequestMsg.messageID.len = sizeof (msgNum);
+
+ PKIX_PL_NSSCALLRV(LDAPDEFAULTCLIENT, encoded, SEC_ASN1EncodeItem,
+ (arena, NULL, (void *)&msg, PKIX_PL_LDAPMessageTemplate));
+ if (!encoded) {
+ PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED);
+ }
+
+ *pAbandonMsg = encoded;
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_DecodeBindResponse
+ * DESCRIPTION:
+ *
+ * This function decodes the encoded data pointed to by "src", using the arena
+ * pointed to by "arena", storing the decoded LDAPMessage at "pBindResponse"
+ * and the decoding status at "pStatus".
+ *
+ * PARAMETERS:
+ * "arena"
+ * The address of the PLArenaPool to be used in decoding the message. Must
+ * be non-NULL.
+ * "src"
+ * The address of the SECItem containing the DER- (or BER-)encoded string.
+ * Must be non-NULL.
+ * "pBindResponse"
+ * The address at which the LDAPMessage is stored, if the decoding is
+ * successful (the returned status is SECSuccess). Must be non-NULL.
+ * "pStatus"
+ * The address at which the decoding status is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_DecodeBindResponse(
+ PLArenaPool *arena,
+ SECItem *src,
+ LDAPMessage *pBindResponse,
+ SECStatus *pStatus,
+ void *plContext)
+{
+ SECStatus rv = SECFailure;
+ LDAPMessage response;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_DecodeBindResponse");
+ PKIX_NULLCHECK_FOUR(arena, src, pBindResponse, pStatus);
+
+ PKIX_PL_NSSCALL
+ (LDAPDEFAULTCLIENT,
+ PORT_Memset,
+ (&response, 0, sizeof (LDAPMessage)));
+
+ PKIX_PL_NSSCALLRV(LDAPDEFAULTCLIENT, rv, SEC_ASN1DecodeItem,
+ (arena, &response, PKIX_PL_LDAPMessageTemplate, src));
+
+ if (rv == SECSuccess) {
+ *pBindResponse = response;
+ }
+
+ *pStatus = rv;
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_VerifyBindResponse
+ * DESCRIPTION:
+ *
+ * This function verifies that the contents of the message in the rcvbuf of
+ * the LdapDefaultClient object pointed to by "client", and whose length is
+ * provided by "buflen", is a response to a successful Bind.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "buflen"
+ * The value of the number of bytes in the receive buffer.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_VerifyBindResponse(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_UInt32 bufLen,
+ void *plContext)
+{
+ SECItem decode = {siBuffer, NULL, 0};
+ SECStatus rv = SECFailure;
+ LDAPMessage msg;
+ LDAPBindResponse *ldapBindResponse = NULL;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_VerifyBindResponse");
+ PKIX_NULLCHECK_TWO(client, client->rcvBuf);
+
+ decode.data = (unsigned char *)(client->rcvBuf);
+ decode.len = bufLen;
+
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_DecodeBindResponse
+ (client->arena, &decode, &msg, &rv, plContext),
+ PKIX_LDAPDEFAULTCLIENTDECODEBINDRESPONSEFAILED);
+
+ if (rv == SECSuccess) {
+ ldapBindResponse = &msg.protocolOp.op.bindResponseMsg;
+ if (*(ldapBindResponse->resultCode.data) == SUCCESS) {
+ client->connectStatus = BOUND;
+ } else {
+ PKIX_ERROR(PKIX_BINDREJECTEDBYSERVER);
+ }
+ } else {
+ PKIX_ERROR(PKIX_CANTDECODEBINDRESPONSEFROMSERVER);
+ }
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_RecvCheckComplete
+ * DESCRIPTION:
+ *
+ * This function determines whether the current response in the
+ * LdapDefaultClient pointed to by "client" is complete, in the sense that all
+ * bytes required to satisfy the message length field in the encoding have been
+ * received. If so, the pointer to input data is updated to reflect the number
+ * of bytes consumed, provided by "bytesProcessed". The state machine flag
+ * pointed to by "pKeepGoing" is updated to indicate whether processing can
+ * continue without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "bytesProcessed"
+ * The UInt32 value of the number of bytes consumed from the current
+ * buffer.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_RecvCheckComplete(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_UInt32 bytesProcessed,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_Boolean complete = PKIX_FALSE;
+ SECStatus rv = SECFailure;
+ LDAPMessageType messageType = 0;
+ LDAPResultCode resultCode = 0;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_RecvCheckComplete");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ PKIX_CHECK(pkix_pl_LdapResponse_IsComplete
+ (client->currentResponse, &complete, plContext),
+ PKIX_LDAPRESPONSEISCOMPLETEFAILED);
+
+ if (complete) {
+ PKIX_CHECK(pkix_pl_LdapResponse_Decode
+ (client->arena, client->currentResponse, &rv, plContext),
+ PKIX_LDAPRESPONSEDECODEFAILED);
+
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_CANTDECODESEARCHRESPONSEFROMSERVER);
+ }
+
+ PKIX_CHECK(pkix_pl_LdapResponse_GetMessageType
+ (client->currentResponse, &messageType, plContext),
+ PKIX_LDAPRESPONSEGETMESSAGETYPEFAILED);
+
+ if (messageType == LDAP_SEARCHRESPONSEENTRY_TYPE) {
+
+ if (client->entriesFound == NULL) {
+ PKIX_CHECK(PKIX_List_Create
+ (&(client->entriesFound), plContext),
+ PKIX_LISTCREATEFAILED);
+ }
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (client->entriesFound,
+ (PKIX_PL_Object *)client->currentResponse,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(client->currentResponse);
+
+ /* current receive buffer empty? */
+ if (client->currentBytesAvailable == 0) {
+ client->connectStatus = RECV;
+ *pKeepGoing = PKIX_TRUE;
+ } else {
+ client->connectStatus = RECV_INITIAL;
+ client->currentInPtr = &((char *)
+ (client->currentInPtr))[bytesProcessed];
+ *pKeepGoing = PKIX_TRUE;
+ }
+
+ } else if (messageType == LDAP_SEARCHRESPONSERESULT_TYPE) {
+ PKIX_CHECK(pkix_pl_LdapResponse_GetResultCode
+ (client->currentResponse,
+ &resultCode,
+ plContext),
+ PKIX_LDAPRESPONSEGETRESULTCODEFAILED);
+
+ if ((client->entriesFound == NULL) &&
+ ((resultCode == SUCCESS) ||
+ (resultCode == NOSUCHOBJECT))) {
+ PKIX_CHECK(PKIX_List_Create
+ (&(client->entriesFound), plContext),
+ PKIX_LISTCREATEFAILED);
+ } else if (resultCode == SUCCESS) {
+ PKIX_CHECK(PKIX_List_SetImmutable
+ (client->entriesFound, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+ PKIX_CHECK(PKIX_PL_HashTable_Add
+ (client->cachePtr,
+ (PKIX_PL_Object *)client->currentRequest,
+ (PKIX_PL_Object *)client->entriesFound,
+ plContext),
+ PKIX_HASHTABLEADDFAILED);
+ } else {
+ PKIX_ERROR(PKIX_UNEXPECTEDRESULTCODEINRESPONSE);
+ }
+
+ client->connectStatus = BOUND;
+ *pKeepGoing = PKIX_FALSE;
+ PKIX_DECREF(client->currentResponse);
+
+ } else {
+ PKIX_ERROR(PKIX_SEARCHRESPONSEPACKETOFUNKNOWNTYPE);
+ }
+ } else {
+ client->connectStatus = RECV;
+ *pKeepGoing = PKIX_TRUE;
+ }
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/* --Private-LdapDefaultClient-Object-Functions------------------------- */
+
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_InitiateRequest(
+ PKIX_PL_LdapClient *client,
+ LDAPRequestParams *requestParams,
+ void **pPollDesc,
+ PKIX_List **pResponse,
+ void *plContext);
+
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_ResumeRequest(
+ PKIX_PL_LdapClient *client,
+ void **pPollDesc,
+ PKIX_List **pResponse,
+ void *plContext);
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_CreateHelper
+ * DESCRIPTION:
+ *
+ * This function creates a new LdapDefaultClient using the Socket pointed to
+ * by "socket", the PRIntervalTime pointed to by "timeout", and the
+ * LDAPBindAPI pointed to by "bindAPI", and stores the result at "pClient".
+ *
+ * A value of zero for "timeout" means the LDAPClient will use non-blocking
+ * I/O.
+ *
+ * PARAMETERS:
+ * "socket"
+ * Address of the Socket to be used for the client. Must be non-NULL.
+ * "bindAPI"
+ * The address of the LDAPBindAPI containing the Bind information to be
+ * encoded in the Bind message.
+ * "pClient"
+ * The address at which the created LdapDefaultClient is to be stored.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapDefaultClient_CreateHelper(
+ PKIX_PL_Socket *socket,
+ LDAPBindAPI *bindAPI,
+ PKIX_PL_LdapDefaultClient **pClient,
+ void *plContext)
+{
+ PKIX_PL_HashTable *ht;
+ PKIX_PL_LdapDefaultClient *ldapDefaultClient = NULL;
+ PKIX_PL_Socket_Callback *callbackList;
+ PRFileDesc *fileDesc = NULL;
+ PLArenaPool *arena = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_CreateHelper");
+ PKIX_NULLCHECK_TWO(socket, pClient);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_LDAPDEFAULTCLIENT_TYPE,
+ sizeof (PKIX_PL_LdapDefaultClient),
+ (PKIX_PL_Object **)&ldapDefaultClient,
+ plContext),
+ PKIX_COULDNOTCREATELDAPDEFAULTCLIENTOBJECT);
+
+ ldapDefaultClient->vtable.initiateFcn =
+ pkix_pl_LdapDefaultClient_InitiateRequest;
+ ldapDefaultClient->vtable.resumeFcn =
+ pkix_pl_LdapDefaultClient_ResumeRequest;
+
+ PKIX_CHECK(pkix_pl_Socket_GetPRFileDesc
+ (socket, &fileDesc, plContext),
+ PKIX_SOCKETGETPRFILEDESCFAILED);
+
+ ldapDefaultClient->pollDesc.fd = fileDesc;
+ ldapDefaultClient->pollDesc.in_flags = 0;
+ ldapDefaultClient->pollDesc.out_flags = 0;
+
+ ldapDefaultClient->bindAPI = bindAPI;
+
+ PKIX_CHECK(PKIX_PL_HashTable_Create
+ (LDAP_CACHEBUCKETS, 0, &ht, plContext),
+ PKIX_HASHTABLECREATEFAILED);
+
+ ldapDefaultClient->cachePtr = ht;
+
+ PKIX_CHECK(pkix_pl_Socket_GetCallbackList
+ (socket, &callbackList, plContext),
+ PKIX_SOCKETGETCALLBACKLISTFAILED);
+
+ ldapDefaultClient->callbackList = callbackList;
+
+ PKIX_INCREF(socket);
+ ldapDefaultClient->clientSocket = socket;
+
+ ldapDefaultClient->messageID = 0;
+
+ ldapDefaultClient->bindAPI = bindAPI;
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!arena) {
+ PKIX_ERROR_FATAL(PKIX_OUTOFMEMORY);
+ }
+ ldapDefaultClient->arena = arena;
+
+ ldapDefaultClient->sendBuf = NULL;
+ ldapDefaultClient->bytesToWrite = 0;
+
+ PKIX_CHECK(PKIX_PL_Malloc
+ (RCVBUFSIZE, &ldapDefaultClient->rcvBuf, plContext),
+ PKIX_MALLOCFAILED);
+ ldapDefaultClient->capacity = RCVBUFSIZE;
+
+ ldapDefaultClient->bindMsg = NULL;
+ ldapDefaultClient->bindMsgLen = 0;
+
+ ldapDefaultClient->entriesFound = NULL;
+ ldapDefaultClient->currentRequest = NULL;
+ ldapDefaultClient->currentResponse = NULL;
+
+ *pClient = ldapDefaultClient;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(ldapDefaultClient);
+ }
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_LdapDefaultClient_Create
+ * DESCRIPTION:
+ *
+ * This function creates a new LdapDefaultClient using the PRNetAddr pointed to
+ * by "sockaddr", the PRIntervalTime pointed to by "timeout", and the
+ * LDAPBindAPI pointed to by "bindAPI", and stores the result at "pClient".
+ *
+ * A value of zero for "timeout" means the LDAPClient will use non-blocking
+ * I/O.
+ *
+ * PARAMETERS:
+ * "sockaddr"
+ * Address of the PRNetAddr to be used for the socket connection. Must be
+ * non-NULL.
+ * "timeout"
+ * The PRIntervalTime to be used in I/O requests for this client.
+ * "bindAPI"
+ * The address of the LDAPBindAPI containing the Bind information to be
+ * encoded in the Bind message.
+ * "pClient"
+ * The address at which the created LdapDefaultClient is to be stored.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+PKIX_PL_LdapDefaultClient_Create(
+ PRNetAddr *sockaddr,
+ PRIntervalTime timeout,
+ LDAPBindAPI *bindAPI,
+ PKIX_PL_LdapDefaultClient **pClient,
+ void *plContext)
+{
+ PRErrorCode status = 0;
+ PKIX_PL_Socket *socket = NULL;
+ PKIX_PL_LdapDefaultClient *client = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "PKIX_PL_LdapDefaultClient_Create");
+ PKIX_NULLCHECK_TWO(sockaddr, pClient);
+
+ PKIX_CHECK(pkix_pl_Socket_Create
+ (PKIX_FALSE, timeout, sockaddr, &status, &socket, plContext),
+ PKIX_SOCKETCREATEFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_CreateHelper
+ (socket, bindAPI, &client, plContext),
+ PKIX_LDAPDEFAULTCLIENTCREATEHELPERFAILED);
+
+ /* Did Socket_Create say the connection was made? */
+ if (status == 0) {
+ if (client->bindAPI != NULL) {
+ client->connectStatus = CONNECTED;
+ } else {
+ client->connectStatus = BOUND;
+ }
+ } else {
+ client->connectStatus = CONNECT_PENDING;
+ }
+
+ *pClient = client;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(client);
+ }
+
+ PKIX_DECREF(socket);
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_LdapDefaultClient_CreateByName
+ * DESCRIPTION:
+ *
+ * This function creates a new LdapDefaultClient using the hostname pointed to
+ * by "hostname", the PRIntervalTime pointed to by "timeout", and the
+ * LDAPBindAPI pointed to by "bindAPI", and stores the result at "pClient".
+ *
+ * A value of zero for "timeout" means the LDAPClient will use non-blocking
+ * I/O.
+ *
+ * PARAMETERS:
+ * "hostname"
+ * Address of the hostname to be used for the socket connection. Must be
+ * non-NULL.
+ * "timeout"
+ * The PRIntervalTime to be used in I/O requests for this client.
+ * "bindAPI"
+ * The address of the LDAPBindAPI containing the Bind information to be
+ * encoded in the Bind message.
+ * "pClient"
+ * The address at which the created LdapDefaultClient is to be stored.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+PKIX_PL_LdapDefaultClient_CreateByName(
+ char *hostname,
+ PRIntervalTime timeout,
+ LDAPBindAPI *bindAPI,
+ PKIX_PL_LdapDefaultClient **pClient,
+ void *plContext)
+{
+ PRErrorCode status = 0;
+ PKIX_PL_Socket *socket = NULL;
+ PKIX_PL_LdapDefaultClient *client = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "PKIX_PL_LdapDefaultClient_CreateByName");
+ PKIX_NULLCHECK_TWO(hostname, pClient);
+
+ PKIX_CHECK(pkix_pl_Socket_CreateByName
+ (PKIX_FALSE, timeout, hostname, &status, &socket, plContext),
+ PKIX_SOCKETCREATEBYNAMEFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_CreateHelper
+ (socket, bindAPI, &client, plContext),
+ PKIX_LDAPDEFAULTCLIENTCREATEHELPERFAILED);
+
+ /* Did Socket_Create say the connection was made? */
+ if (status == 0) {
+ if (client->bindAPI != NULL) {
+ client->connectStatus = CONNECTED;
+ } else {
+ client->connectStatus = BOUND;
+ }
+ } else {
+ client->connectStatus = CONNECT_PENDING;
+ }
+
+ *pClient = client;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(client);
+ }
+
+ PKIX_DECREF(socket);
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_PL_LdapDefaultClient *client = NULL;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+ SECItem *encoded = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_LDAPDEFAULTCLIENT_TYPE, plContext),
+ PKIX_OBJECTNOTANLDAPDEFAULTCLIENT);
+
+ client = (PKIX_PL_LdapDefaultClient *)object;
+
+ switch (client->connectStatus) {
+ case CONNECT_PENDING:
+ break;
+ case CONNECTED:
+ case BIND_PENDING:
+ case BIND_RESPONSE:
+ case BIND_RESPONSE_PENDING:
+ case BOUND:
+ case SEND_PENDING:
+ case RECV:
+ case RECV_PENDING:
+ case RECV_INITIAL:
+ case RECV_NONINITIAL:
+ case ABANDON_PENDING:
+ if (client->bindAPI != NULL) {
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_MakeUnbind
+ (client->arena,
+ ++(client->messageID),
+ &encoded,
+ plContext),
+ PKIX_LDAPDEFAULTCLIENTMAKEUNBINDFAILED);
+
+ callbackList =
+ (PKIX_PL_Socket_Callback *)(client->callbackList);
+ PKIX_CHECK(callbackList->sendCallback
+ (client->clientSocket,
+ encoded->data,
+ encoded->len,
+ &bytesWritten,
+ plContext),
+ PKIX_SOCKETSENDFAILED);
+ }
+ break;
+ default:
+ PKIX_ERROR(PKIX_LDAPDEFAULTCLIENTINILLEGALSTATE);
+ }
+
+ PKIX_DECREF(client->cachePtr);
+ PKIX_DECREF(client->clientSocket);
+ PKIX_DECREF(client->entriesFound);
+ PKIX_DECREF(client->currentRequest);
+ PKIX_DECREF(client->currentResponse);
+
+ PKIX_CHECK(PKIX_PL_Free
+ (client->rcvBuf, plContext), PKIX_FREEFAILED);
+
+ PKIX_PL_NSSCALL
+ (LDAPDEFAULTCLIENT,
+ PORT_FreeArena,
+ (client->arena, PR_FALSE));
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_LdapDefaultClient *ldapDefaultClient = NULL;
+ PKIX_UInt32 tempHash = 0;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_LDAPDEFAULTCLIENT_TYPE, plContext),
+ PKIX_OBJECTNOTANLDAPDEFAULTCLIENT);
+
+ ldapDefaultClient = (PKIX_PL_LdapDefaultClient *)object;
+
+ PKIX_CHECK(PKIX_PL_Object_Hashcode
+ ((PKIX_PL_Object *)ldapDefaultClient->clientSocket,
+ &tempHash,
+ plContext),
+ PKIX_SOCKETHASHCODEFAILED);
+
+ if (ldapDefaultClient->bindAPI != NULL) {
+ tempHash = (tempHash << 7) +
+ ldapDefaultClient->bindAPI->selector;
+ }
+
+ *pHashcode = tempHash;
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_Equals
+ * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Int32 *pResult,
+ void *plContext)
+{
+ PKIX_PL_LdapDefaultClient *firstClientContext = NULL;
+ PKIX_PL_LdapDefaultClient *secondClientContext = NULL;
+ PKIX_Int32 compare = 0;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ *pResult = PKIX_FALSE;
+
+ PKIX_CHECK(pkix_CheckTypes
+ (firstObject,
+ secondObject,
+ PKIX_LDAPDEFAULTCLIENT_TYPE,
+ plContext),
+ PKIX_OBJECTNOTANLDAPDEFAULTCLIENT);
+
+ firstClientContext = (PKIX_PL_LdapDefaultClient *)firstObject;
+ secondClientContext = (PKIX_PL_LdapDefaultClient *)secondObject;
+
+ if (firstClientContext == secondClientContext) {
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_Equals
+ ((PKIX_PL_Object *)firstClientContext->clientSocket,
+ (PKIX_PL_Object *)secondClientContext->clientSocket,
+ &compare,
+ plContext),
+ PKIX_SOCKETEQUALSFAILED);
+
+ if (!compare) {
+ goto cleanup;
+ }
+
+ if (PKIX_EXACTLY_ONE_NULL
+ (firstClientContext->bindAPI, secondClientContext->bindAPI)) {
+ goto cleanup;
+ }
+
+ if (firstClientContext->bindAPI) {
+ if (firstClientContext->bindAPI->selector !=
+ secondClientContext->bindAPI->selector) {
+ goto cleanup;
+ }
+ }
+
+ *pResult = PKIX_TRUE;
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_RegisterSelf
+ *
+ * DESCRIPTION:
+ * Registers PKIX_PL_LDAPDEFAULTCLIENT_TYPE and its related
+ * functions with systemClasses[]
+ *
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_LdapDefaultClient_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_RegisterSelf");
+
+ entry.description = "LdapDefaultClient";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_LdapDefaultClient);
+ entry.destructor = pkix_pl_LdapDefaultClient_Destroy;
+ entry.equalsFunction = pkix_pl_LdapDefaultClient_Equals;
+ entry.hashcodeFunction = pkix_pl_LdapDefaultClient_Hashcode;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = NULL;
+
+ systemClasses[PKIX_LDAPDEFAULTCLIENT_TYPE] = entry;
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_GetPollDesc
+ * DESCRIPTION:
+ *
+ * This function retrieves the PRPollDesc from the LdapDefaultClient
+ * pointed to by "context" and stores the address at "pPollDesc".
+ *
+ * PARAMETERS:
+ * "context"
+ * The LdapDefaultClient whose PRPollDesc is desired. Must be non-NULL.
+ * "pPollDesc"
+ * Address where PRPollDesc will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapDefaultClient_GetPollDesc(
+ PKIX_PL_LdapDefaultClient *context,
+ PRPollDesc **pPollDesc,
+ void *plContext)
+{
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_GetPollDesc");
+ PKIX_NULLCHECK_TWO(context, pPollDesc);
+
+ *pPollDesc = &(context->pollDesc);
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/* --Private-Ldap-CertStore-I/O-Functions---------------------------- */
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_ConnectContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether a socket Connect initiated earlier for the
+ * CertStore embodied in the LdapDefaultClient "client" has completed, and
+ * stores in "pKeepGoing" a flag indicating whether processing can continue
+ * without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_ConnectContinue(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_PL_Socket_Callback *callbackList;
+ PRErrorCode status;
+ PKIX_Boolean keepGoing = PKIX_FALSE;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_ConnectContinue");
+ PKIX_NULLCHECK_ONE(client);
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->connectcontinueCallback
+ (client->clientSocket, &status, plContext),
+ PKIX_SOCKETCONNECTCONTINUEFAILED);
+
+ if (status == 0) {
+ if (client->bindAPI != NULL) {
+ client->connectStatus = CONNECTED;
+ } else {
+ client->connectStatus = BOUND;
+ }
+ keepGoing = PKIX_FALSE;
+ } else if (status != PR_IN_PROGRESS_ERROR) {
+ PKIX_ERROR(PKIX_UNEXPECTEDERRORINESTABLISHINGCONNECTION);
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+
+ *pKeepGoing = keepGoing;
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_Bind
+ * DESCRIPTION:
+ *
+ * This function creates and sends the LDAP-protocol Bind message for the
+ * CertStore embodied in the LdapDefaultClient "client", and stores in
+ * "pKeepGoing" a flag indicating whether processing can continue without
+ * further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_Bind(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ SECItem *encoded = NULL;
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_PL_Socket_Callback *callbackList;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Bind");
+ PKIX_NULLCHECK_ONE(client);
+
+ /* if we have not yet constructed the BIND message, build it now */
+ if (!(client->bindMsg)) {
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_MakeBind
+ (client->arena,
+ 3,
+ client->bindAPI,
+ client->messageID,
+ &encoded,
+ plContext),
+ PKIX_LDAPDEFAULTCLIENTMAKEBINDFAILED);
+ client->bindMsg = encoded->data;
+ client->bindMsgLen = encoded->len;
+ }
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->sendCallback
+ (client->clientSocket,
+ client->bindMsg,
+ client->bindMsgLen,
+ &bytesWritten,
+ plContext),
+ PKIX_SOCKETSENDFAILED);
+
+ client->lastIO = PR_Now();
+
+ if (bytesWritten < 0) {
+ client->connectStatus = BIND_PENDING;
+ *pKeepGoing = PKIX_FALSE;
+ } else {
+ client->connectStatus = BIND_RESPONSE;
+ *pKeepGoing = PKIX_TRUE;
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_BindContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether the LDAP-protocol Bind message for the
+ * CertStore embodied in the LdapDefaultClient "client" has completed, and
+ * stores in "pKeepGoing" a flag indicating whether processing can continue
+ * without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *pkix_pl_LdapDefaultClient_BindContinue(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_BindContinue");
+ PKIX_NULLCHECK_ONE(client);
+
+ *pKeepGoing = PKIX_FALSE;
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->pollCallback
+ (client->clientSocket, &bytesWritten, NULL, plContext),
+ PKIX_SOCKETPOLLFAILED);
+
+ /*
+ * If the send completed we can proceed to try for the
+ * response. If the send did not complete we will have
+ * continue to poll.
+ */
+ if (bytesWritten >= 0) {
+
+ client->connectStatus = BIND_RESPONSE;
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+
+ *pKeepGoing = PKIX_TRUE;
+ }
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_BindResponse
+ * DESCRIPTION:
+ *
+ * This function attempts to read the LDAP-protocol BindResponse message for
+ * the CertStore embodied in the LdapDefaultClient "client", and stores in
+ * "pKeepGoing" a flag indicating whether processing can continue without
+ * further input.
+ *
+ * If a BindResponse is received with a Result code of 0 (success), we
+ * continue with the connection. If a non-zero Result code is received,
+ * we throw an Error. Some more sophisticated handling of that condition
+ * might be in order in the future.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_BindResponse(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_Int32 bytesRead = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_BindResponse");
+ PKIX_NULLCHECK_TWO(client, client->rcvBuf);
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->recvCallback
+ (client->clientSocket,
+ client->rcvBuf,
+ client->capacity,
+ &bytesRead,
+ plContext),
+ PKIX_SOCKETRECVFAILED);
+
+ client->lastIO = PR_Now();
+
+ if (bytesRead > 0) {
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_VerifyBindResponse
+ (client, bytesRead, plContext),
+ PKIX_LDAPDEFAULTCLIENTVERIFYBINDRESPONSEFAILED);
+ /*
+ * XXX What should we do if failure? At present if
+ * VerifyBindResponse throws an Error, we do too.
+ */
+ client->connectStatus = BOUND;
+ } else {
+ client->connectStatus = BIND_RESPONSE_PENDING;
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+
+ *pKeepGoing = PKIX_TRUE;
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_BindResponseContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether the LDAP-protocol BindResponse message for
+ * the CertStore embodied in the LdapDefaultClient "client" has completed, and
+ * stores in "pKeepGoing" a flag indicating whether processing can continue
+ * without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_BindResponseContinue(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_Int32 bytesRead = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_BindResponseContinue");
+ PKIX_NULLCHECK_ONE(client);
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->pollCallback
+ (client->clientSocket, NULL, &bytesRead, plContext),
+ PKIX_SOCKETPOLLFAILED);
+
+ if (bytesRead > 0) {
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_VerifyBindResponse
+ (client, bytesRead, plContext),
+ PKIX_LDAPDEFAULTCLIENTVERIFYBINDRESPONSEFAILED);
+ client->connectStatus = BOUND;
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+
+ *pKeepGoing = PKIX_TRUE;
+ } else {
+ *pKeepGoing = PKIX_FALSE;
+ }
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_Send
+ * DESCRIPTION:
+ *
+ * This function creates and sends an LDAP-protocol message for the
+ * CertStore embodied in the LdapDefaultClient "client", and stores in
+ * "pKeepGoing" a flag indicating whether processing can continue without
+ * further input, and at "pBytesTransferred" the number of bytes sent.
+ *
+ * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use
+ * and that transmission has not completed.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "pBytesTransferred"
+ * The address at which the number of bytes sent is stored. Must be
+ * non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_Send(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ PKIX_UInt32 *pBytesTransferred,
+ void *plContext)
+{
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Send");
+ PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred);
+
+ *pKeepGoing = PKIX_FALSE;
+
+ /* Do we have anything waiting to go? */
+ if (client->sendBuf) {
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->sendCallback
+ (client->clientSocket,
+ client->sendBuf,
+ client->bytesToWrite,
+ &bytesWritten,
+ plContext),
+ PKIX_SOCKETSENDFAILED);
+
+ client->lastIO = PR_Now();
+
+ /*
+ * If the send completed we can proceed to try for the
+ * response. If the send did not complete we will have
+ * to poll for completion later.
+ */
+ if (bytesWritten >= 0) {
+ client->sendBuf = NULL;
+ client->connectStatus = RECV;
+ *pKeepGoing = PKIX_TRUE;
+
+ } else {
+ *pKeepGoing = PKIX_FALSE;
+ client->connectStatus = SEND_PENDING;
+ }
+
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+
+ *pBytesTransferred = bytesWritten;
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_SendContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether the sending of the LDAP-protocol message
+ * for the CertStore embodied in the LdapDefaultClient "client" has completed,
+ * and stores in "pKeepGoing" a flag indicating whether processing can continue
+ * without further input, and at "pBytesTransferred" the number of bytes sent.
+ *
+ * If "pBytesTransferred" is zero, it indicates that non-blocking I/O is in use
+ * and that transmission has not completed.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "pBytesTransferred"
+ * The address at which the number of bytes sent is stored. Must be
+ * non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_SendContinue(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ PKIX_UInt32 *pBytesTransferred,
+ void *plContext)
+{
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_SendContinue");
+ PKIX_NULLCHECK_THREE(client, pKeepGoing, pBytesTransferred);
+
+ *pKeepGoing = PKIX_FALSE;
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->pollCallback
+ (client->clientSocket, &bytesWritten, NULL, plContext),
+ PKIX_SOCKETPOLLFAILED);
+
+ /*
+ * If the send completed we can proceed to try for the
+ * response. If the send did not complete we will have
+ * continue to poll.
+ */
+ if (bytesWritten >= 0) {
+ client->sendBuf = NULL;
+ client->connectStatus = RECV;
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+
+ *pKeepGoing = PKIX_TRUE;
+ }
+
+ *pBytesTransferred = bytesWritten;
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_Recv
+ * DESCRIPTION:
+ *
+ * This function receives an LDAP-protocol message for the CertStore embodied
+ * in the LdapDefaultClient "client", and stores in "pKeepGoing" a flag
+ * indicating whether processing can continue without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_Recv(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_Int32 bytesRead = 0;
+ PKIX_UInt32 bytesToRead = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Recv");
+ PKIX_NULLCHECK_THREE(client, pKeepGoing, client->rcvBuf);
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ /*
+ * If we attempt to fill our buffer with every read, we increase
+ * the risk of an ugly situation: one or two bytes of a new message
+ * left over at the end of processing one message. With such a
+ * fragment, we can't decode a byte count and so won't know how much
+ * space to allocate for the next LdapResponse. We try to avoid that
+ * case by reading just enough to complete the current message, unless
+ * there will be at least MINIMUM_MSG_LENGTH bytes left over.
+ */
+ if (client->currentResponse) {
+ PKIX_CHECK(pkix_pl_LdapResponse_GetCapacity
+ (client->currentResponse, &bytesToRead, plContext),
+ PKIX_LDAPRESPONSEGETCAPACITYFAILED);
+ if ((bytesToRead > client->capacity) ||
+ ((bytesToRead + MINIMUM_MSG_LENGTH) < client->capacity)) {
+ bytesToRead = client->capacity;
+ }
+ } else {
+ bytesToRead = client->capacity;
+ }
+
+ client->currentBytesAvailable = 0;
+
+ PKIX_CHECK(callbackList->recvCallback
+ (client->clientSocket,
+ (void *)client->rcvBuf,
+ bytesToRead,
+ &bytesRead,
+ plContext),
+ PKIX_SOCKETRECVFAILED);
+
+ client->currentInPtr = client->rcvBuf;
+ client->lastIO = PR_Now();
+
+ if (bytesRead > 0) {
+ client->currentBytesAvailable = bytesRead;
+ client->connectStatus = RECV_INITIAL;
+ *pKeepGoing = PKIX_TRUE;
+ } else {
+ client->connectStatus = RECV_PENDING;
+ *pKeepGoing = PKIX_FALSE;
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_RecvContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether the receiving of the LDAP-protocol message
+ * for the CertStore embodied in the LdapDefaultClient "client" has completed,
+ * and stores in "pKeepGoing" a flag indicating whether processing can continue
+ * without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_RecvContinue(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_Int32 bytesRead = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_RecvContinue");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->pollCallback
+ (client->clientSocket, NULL, &bytesRead, plContext),
+ PKIX_SOCKETPOLLFAILED);
+
+ if (bytesRead > 0) {
+ client->currentBytesAvailable += bytesRead;
+ client->connectStatus = RECV_INITIAL;
+ *pKeepGoing = PKIX_TRUE;
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+ } else {
+ *pKeepGoing = PKIX_FALSE;
+ }
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_AbandonContinue
+ * DESCRIPTION:
+ *
+ * This function determines whether the abandon-message request of the
+ * LDAP-protocol message for the CertStore embodied in the LdapDefaultClient
+ * "client" has completed, and stores in "pKeepGoing" a flag indicating whether
+ * processing can continue without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_AbandonContinue(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_AbandonContinue");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+
+ PKIX_CHECK(callbackList->pollCallback
+ (client->clientSocket, &bytesWritten, NULL, plContext),
+ PKIX_SOCKETPOLLFAILED);
+
+ if (bytesWritten > 0) {
+ client->connectStatus = BOUND;
+ *pKeepGoing = PKIX_TRUE;
+
+ PKIX_CHECK(PKIX_PL_Object_InvalidateCache
+ ((PKIX_PL_Object *)client, plContext),
+ PKIX_OBJECTINVALIDATECACHEFAILED);
+ } else {
+ *pKeepGoing = PKIX_FALSE;
+ }
+
+cleanup:
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_RecvInitial
+ * DESCRIPTION:
+ *
+ * This function processes the contents of the first buffer of a received
+ * LDAP-protocol message for the CertStore embodied in the LdapDefaultClient
+ * "client", and stores in "pKeepGoing" a flag indicating whether processing can
+ * continue without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_RecvInitial(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+ unsigned char *msgBuf = NULL;
+ unsigned char *to = NULL;
+ unsigned char *from = NULL;
+ PKIX_UInt32 dataIndex = 0;
+ PKIX_UInt32 messageIdLen = 0;
+ PKIX_UInt32 messageLength = 0;
+ PKIX_UInt32 sizeofLength = 0;
+ PKIX_UInt32 bytesProcessed = 0;
+ unsigned char messageChar = 0;
+ LDAPMessageType messageType = 0;
+ PKIX_Int32 bytesRead = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_RecvInitial");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ /*
+ * Is there an LDAPResponse in progress? I.e., have we
+ * already processed the tag and length at the beginning of
+ * the message?
+ */
+ if (client->currentResponse) {
+ client->connectStatus = RECV_NONINITIAL;
+ *pKeepGoing = PKIX_TRUE;
+ goto cleanup;
+ }
+ msgBuf = client->currentInPtr;
+
+ /* Do we have enough of the message to decode the message length? */
+ if (client->currentBytesAvailable < MINIMUM_MSG_LENGTH) {
+ /*
+ * No! Move these few bytes to the beginning of rcvBuf
+ * and hang another read.
+ */
+
+ to = (unsigned char *)client->rcvBuf;
+ from = client->currentInPtr;
+ for (dataIndex = 0;
+ dataIndex < client->currentBytesAvailable;
+ dataIndex++) {
+ *to++ = *from++;
+ }
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+ PKIX_CHECK(callbackList->recvCallback
+ (client->clientSocket,
+ (void *)to,
+ client->capacity - client->currentBytesAvailable,
+ &bytesRead,
+ plContext),
+ PKIX_SOCKETRECVFAILED);
+
+ client->currentInPtr = client->rcvBuf;
+ client->lastIO = PR_Now();
+
+ if (bytesRead <= 0) {
+ client->connectStatus = RECV_PENDING;
+ *pKeepGoing = PKIX_FALSE;
+ goto cleanup;
+ } else {
+ client->currentBytesAvailable += bytesRead;
+ }
+ }
+
+ /*
+ * We have to determine whether the response is an entry, with
+ * application-specific tag LDAP_SEARCHRESPONSEENTRY_TYPE, or a
+ * resultCode, with application tag LDAP_SEARCHRESPONSERESULT_TYPE.
+ * First, we have to figure out where to look for the tag.
+ */
+
+ /* Is the message length short form (one octet) or long form? */
+ if ((msgBuf[1] & 0x80) != 0) {
+ sizeofLength = msgBuf[1] & 0x7F;
+ for (dataIndex = 0; dataIndex < sizeofLength; dataIndex++) {
+ messageLength =
+ (messageLength << 8) + msgBuf[dataIndex + 2];
+ }
+ } else {
+ messageLength = msgBuf[1];
+ }
+
+ /* How many bytes did the messageID require? */
+ messageIdLen = msgBuf[dataIndex + 3];
+
+ messageChar = msgBuf[dataIndex + messageIdLen + 4];
+
+ /* Are we looking at an Entry message or a ResultCode message? */
+ if ((SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION |
+ LDAP_SEARCHRESPONSEENTRY_TYPE) == messageChar) {
+
+ messageType = LDAP_SEARCHRESPONSEENTRY_TYPE;
+
+ } else if ((SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION |
+ LDAP_SEARCHRESPONSERESULT_TYPE) == messageChar) {
+
+ messageType = LDAP_SEARCHRESPONSERESULT_TYPE;
+
+ } else {
+
+ PKIX_ERROR(PKIX_SEARCHRESPONSEPACKETOFUNKNOWNTYPE);
+
+ }
+
+ /*
+ * messageLength is the length from (tag, length, value).
+ * We have to allocate space for the tag and length bits too.
+ */
+ PKIX_CHECK(pkix_pl_LdapResponse_Create
+ (messageType,
+ messageLength + dataIndex + 2,
+ client->currentBytesAvailable,
+ msgBuf,
+ &bytesProcessed,
+ &(client->currentResponse),
+ plContext),
+ PKIX_LDAPRESPONSECREATEFAILED);
+
+ client->currentBytesAvailable -= bytesProcessed;
+
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_RecvCheckComplete
+ (client, bytesProcessed, pKeepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTRECVCHECKCOMPLETEFAILED);
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_RecvNonInitial
+ * DESCRIPTION:
+ *
+ * This function processes the contents of buffers, after the first, of a
+ * received LDAP-protocol message for the CertStore embodied in the
+ * LdapDefaultClient "client", and stores in "pKeepGoing" a flag indicating
+ * whether processing can continue without further input.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pKeepGoing"
+ * The address at which the Boolean state machine flag is stored to
+ * indicate whether processing can continue without further input.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_RecvNonInitial(
+ PKIX_PL_LdapDefaultClient *client,
+ PKIX_Boolean *pKeepGoing,
+ void *plContext)
+{
+
+ PKIX_UInt32 bytesProcessed = 0;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_RecvNonInitial");
+ PKIX_NULLCHECK_TWO(client, pKeepGoing);
+
+ PKIX_CHECK(pkix_pl_LdapResponse_Append
+ (client->currentResponse,
+ client->currentBytesAvailable,
+ client->currentInPtr,
+ &bytesProcessed,
+ plContext),
+ PKIX_LDAPRESPONSEAPPENDFAILED);
+
+ client->currentBytesAvailable -= bytesProcessed;
+
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_RecvCheckComplete
+ (client, bytesProcessed, pKeepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTRECVCHECKCOMPLETEFAILED);
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_Dispatch
+ * DESCRIPTION:
+ *
+ * This function is the state machine dispatcher for the CertStore embodied in
+ * the LdapDefaultClient pointed to by "client". Results are returned by
+ * changes to various fields in the context.
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_Dispatch(
+ PKIX_PL_LdapDefaultClient *client,
+ void *plContext)
+{
+ PKIX_UInt32 bytesTransferred = 0;
+ PKIX_Boolean keepGoing = PKIX_TRUE;
+
+ PKIX_ENTER(LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_Dispatch");
+ PKIX_NULLCHECK_ONE(client);
+
+ while (keepGoing) {
+ switch (client->connectStatus) {
+ case CONNECT_PENDING:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_ConnectContinue
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTCONNECTCONTINUEFAILED);
+ break;
+ case CONNECTED:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_Bind
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTBINDFAILED);
+ break;
+ case BIND_PENDING:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_BindContinue
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTBINDCONTINUEFAILED);
+ break;
+ case BIND_RESPONSE:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_BindResponse
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTBINDRESPONSEFAILED);
+ break;
+ case BIND_RESPONSE_PENDING:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_BindResponseContinue
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTBINDRESPONSECONTINUEFAILED);
+ break;
+ case BOUND:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_Send
+ (client, &keepGoing, &bytesTransferred, plContext),
+ PKIX_LDAPDEFAULTCLIENTSENDFAILED);
+ break;
+ case SEND_PENDING:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_SendContinue
+ (client, &keepGoing, &bytesTransferred, plContext),
+ PKIX_LDAPDEFAULTCLIENTSENDCONTINUEFAILED);
+ break;
+ case RECV:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_Recv
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTRECVFAILED);
+ break;
+ case RECV_PENDING:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_RecvContinue
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTRECVCONTINUEFAILED);
+ break;
+ case RECV_INITIAL:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_RecvInitial
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTRECVINITIALFAILED);
+ break;
+ case RECV_NONINITIAL:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_RecvNonInitial
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTRECVNONINITIALFAILED);
+ break;
+ case ABANDON_PENDING:
+ PKIX_CHECK
+ (pkix_pl_LdapDefaultClient_AbandonContinue
+ (client, &keepGoing, plContext),
+ PKIX_LDAPDEFAULTCLIENTABANDONCONTINUEFAILED);
+ break;
+ default:
+ PKIX_ERROR(PKIX_LDAPCERTSTOREINILLEGALSTATE);
+ }
+ }
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_MakeAndFilter
+ * DESCRIPTION:
+ *
+ * This function allocates space from the arena pointed to by "arena" to
+ * construct a filter that will match components of the X500Name pointed to by
+ * XXX...
+ *
+ * PARAMETERS:
+ * "arena"
+ * The address of the PLArenaPool used in creating the filter. Must be
+ * non-NULL.
+ * "nameComponent"
+ * The address of a NULL-terminated list of LDAPNameComponents
+ * Must be non-NULL.
+ * "pFilter"
+ * The address at which the result is stored.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_MakeAndFilter(
+ PLArenaPool *arena,
+ LDAPNameComponent **nameComponents,
+ LDAPFilter **pFilter,
+ void *plContext)
+{
+ LDAPFilter **setOfFilter;
+ LDAPFilter *andFilter = NULL;
+ LDAPFilter *currentFilter = NULL;
+ PKIX_UInt32 componentsPresent = 0;
+ void *v = NULL;
+ unsigned char *component = NULL;
+ LDAPNameComponent **componentP = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_LdapDefaultClient_MakeAndFilter");
+ PKIX_NULLCHECK_THREE(arena, nameComponents, pFilter);
+
+ /* count how many components we were provided */
+ for (componentP = nameComponents, componentsPresent = 0;
+ *(componentP++) != NULL;
+ componentsPresent++) {}
+
+ /* Space for (componentsPresent + 1) pointers to LDAPFilter */
+ PKIX_PL_NSSCALLRV(CERTSTORE, v, PORT_ArenaZAlloc,
+ (arena, (componentsPresent + 1)*sizeof(LDAPFilter *)));
+ setOfFilter = (LDAPFilter **)v;
+
+ /* Space for AndFilter and <componentsPresent> EqualFilters */
+ PKIX_PL_NSSCALLRV(CERTSTORE, v, PORT_ArenaZNewArray,
+ (arena, LDAPFilter, componentsPresent + 1));
+ setOfFilter[0] = (LDAPFilter *)v;
+
+ /* Claim the first array element for the ANDFilter */
+ andFilter = setOfFilter[0];
+
+ /* Set ANDFilter to point to the first EqualFilter pointer */
+ andFilter->selector = LDAP_ANDFILTER_TYPE;
+ andFilter->filter.andFilter.filters = setOfFilter;
+
+ currentFilter = andFilter + 1;
+
+ for (componentP = nameComponents, componentsPresent = 0;
+ *(componentP) != NULL; componentP++) {
+ setOfFilter[componentsPresent++] = currentFilter;
+ currentFilter->selector = LDAP_EQUALFILTER_TYPE;
+ component = (*componentP)->attrType;
+ currentFilter->filter.equalFilter.attrType.data = component;
+ currentFilter->filter.equalFilter.attrType.len =
+ PL_strlen((const char *)component);
+ component = (*componentP)->attrValue;
+ currentFilter->filter.equalFilter.attrValue.data = component;
+ currentFilter->filter.equalFilter.attrValue.len =
+ PL_strlen((const char *)component);
+ currentFilter++;
+ }
+
+ setOfFilter[componentsPresent] = NULL;
+
+ *pFilter = andFilter;
+
+ PKIX_RETURN(CERTSTORE);
+
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_InitiateRequest
+ * DESCRIPTION:
+ *
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "requestParams"
+ * The address of an LdapClientParams object. Must be non-NULL.
+ * "pPollDesc"
+ * The location where the address of the PRPollDesc is stored, if the
+ * client returns with I/O pending.
+ * "pResponse"
+ * The address where the List of LDAPResponses, or NULL for an
+ * unfinished request, is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_InitiateRequest(
+ PKIX_PL_LdapClient *genericClient,
+ LDAPRequestParams *requestParams,
+ void **pPollDesc,
+ PKIX_List **pResponse,
+ void *plContext)
+{
+ PKIX_List *searchResponseList = NULL;
+ SECItem *encoded = NULL;
+ LDAPFilter *filter = NULL;
+ PKIX_PL_LdapDefaultClient *client = 0;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT,
+ "pkix_pl_LdapDefaultClient_InitiateRequest");
+ PKIX_NULLCHECK_FOUR(genericClient, requestParams, pPollDesc, pResponse);
+
+ PKIX_CHECK(pkix_CheckType
+ ((PKIX_PL_Object *)genericClient,
+ PKIX_LDAPDEFAULTCLIENT_TYPE,
+ plContext),
+ PKIX_GENERICCLIENTNOTANLDAPDEFAULTCLIENT);
+
+ client = (PKIX_PL_LdapDefaultClient *)genericClient;
+
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_MakeAndFilter
+ (client->arena, requestParams->nc, &filter, plContext),
+ PKIX_LDAPDEFAULTCLIENTMAKEANDFILTERFAILED);
+
+ PKIX_CHECK(pkix_pl_LdapRequest_Create
+ (client->arena,
+ client->messageID++,
+ requestParams->baseObject,
+ requestParams->scope,
+ requestParams->derefAliases,
+ requestParams->sizeLimit,
+ requestParams->timeLimit,
+ PKIX_FALSE, /* attrs only */
+ filter,
+ requestParams->attributes,
+ &client->currentRequest,
+ plContext),
+ PKIX_LDAPREQUESTCREATEFAILED);
+
+ /* check hashtable for matching request */
+ PKIX_CHECK(PKIX_PL_HashTable_Lookup
+ (client->cachePtr,
+ (PKIX_PL_Object *)(client->currentRequest),
+ (PKIX_PL_Object **)&searchResponseList,
+ plContext),
+ PKIX_HASHTABLELOOKUPFAILED);
+
+ if (searchResponseList != NULL) {
+ *pPollDesc = NULL;
+ *pResponse = searchResponseList;
+ PKIX_DECREF(client->currentRequest);
+ goto cleanup;
+ }
+
+ /* It wasn't cached. We'll have to actually send it. */
+
+ PKIX_CHECK(pkix_pl_LdapRequest_GetEncoded
+ (client->currentRequest, &encoded, plContext),
+ PKIX_LDAPREQUESTGETENCODEDFAILED);
+
+ client->sendBuf = encoded->data;
+ client->bytesToWrite = encoded->len;
+
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_Dispatch(client, plContext),
+ PKIX_LDAPDEFAULTCLIENTDISPATCHFAILED);
+
+ /*
+ * It's not enough that we may be done with a particular read.
+ * We're still processing the transaction until we've gotten the
+ * SearchResponseResult message and returned to the BOUND state.
+ * Otherwise we must still have a read pending, and must hold off
+ * on returning results.
+ */
+ if ((client->connectStatus == BOUND) &&
+ (client->entriesFound != NULL)) {
+ *pPollDesc = NULL;
+ *pResponse = client->entriesFound;
+ client->entriesFound = NULL;
+ PKIX_DECREF(client->currentRequest);
+ } else {
+ *pPollDesc = &client->pollDesc;
+ *pResponse = NULL;
+ }
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapDefaultClient_ResumeRequest
+ * DESCRIPTION:
+ *
+ *
+ * PARAMETERS:
+ * "client"
+ * The address of the LdapDefaultClient object. Must be non-NULL.
+ * "pPollDesc"
+ * The location where the address of the PRPollDesc is stored, if the
+ * client returns with I/O pending.
+ * "pResponse"
+ * The address where the List of LDAPResponses, or NULL for an
+ * unfinished request, is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a LdapDefaultClient Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapDefaultClient_ResumeRequest(
+ PKIX_PL_LdapClient *genericClient,
+ void **pPollDesc,
+ PKIX_List **pResponse,
+ void *plContext)
+{
+ PKIX_PL_LdapDefaultClient *client = 0;
+
+ PKIX_ENTER
+ (LDAPDEFAULTCLIENT, "pkix_pl_LdapDefaultClient_ResumeRequest");
+ PKIX_NULLCHECK_THREE(genericClient, pPollDesc, pResponse);
+
+ PKIX_CHECK(pkix_CheckType
+ ((PKIX_PL_Object *)genericClient,
+ PKIX_LDAPDEFAULTCLIENT_TYPE,
+ plContext),
+ PKIX_GENERICCLIENTNOTANLDAPDEFAULTCLIENT);
+
+ client = (PKIX_PL_LdapDefaultClient *)genericClient;
+
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_Dispatch(client, plContext),
+ PKIX_LDAPDEFAULTCLIENTDISPATCHFAILED);
+
+ /*
+ * It's not enough that we may be done with a particular read.
+ * We're still processing the transaction until we've gotten the
+ * SearchResponseResult message and returned to the BOUND state.
+ * Otherwise we must still have a read pending, and must hold off
+ * on returning results.
+ */
+ if ((client->connectStatus == BOUND) &&
+ (client->entriesFound != NULL)) {
+ *pPollDesc = NULL;
+ *pResponse = client->entriesFound;
+ client->entriesFound = NULL;
+ PKIX_DECREF(client->currentRequest);
+ } else {
+ *pPollDesc = &client->pollDesc;
+ *pResponse = NULL;
+ }
+
+cleanup:
+
+ PKIX_RETURN(LDAPDEFAULTCLIENT);
+
+}
+
+/* --Public-LdapDefaultClient-Functions----------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_LdapDefaultClient_AbandonRequest
+ * DESCRIPTION:
+ *
+ * This function creates and sends an LDAP-protocol "Abandon" message to the
+ * server connected to the LdapDefaultClient pointed to by "client".
+ *
+ * PARAMETERS:
+ * "client"
+ * The LdapDefaultClient whose connection is to be abandoned. Must be
+ * non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+PKIX_PL_LdapDefaultClient_AbandonRequest(
+ PKIX_PL_LdapDefaultClient *client,
+ void *plContext)
+{
+ PKIX_Int32 bytesWritten = 0;
+ PKIX_PL_Socket_Callback *callbackList = NULL;
+ SECItem *encoded = NULL;
+
+ PKIX_ENTER(CERTSTORE, "PKIX_PL_LdapDefaultClient_AbandonRequest");
+ PKIX_NULLCHECK_ONE(client);
+
+ if (client->connectStatus == RECV_PENDING) {
+ PKIX_CHECK(pkix_pl_LdapDefaultClient_MakeAbandon
+ (client->arena,
+ (client->messageID) - 1,
+ &encoded,
+ plContext),
+ PKIX_LDAPDEFAULTCLIENTMAKEABANDONFAILED);
+
+ callbackList = (PKIX_PL_Socket_Callback *)(client->callbackList);
+ PKIX_CHECK(callbackList->sendCallback
+ (client->clientSocket,
+ encoded->data,
+ encoded->len,
+ &bytesWritten,
+ plContext),
+ PKIX_SOCKETSENDFAILED);
+
+ if (bytesWritten < 0) {
+ client->connectStatus = ABANDON_PENDING;
+ } else {
+ client->connectStatus = BOUND;
+ }
+ }
+
+ PKIX_DECREF(client->entriesFound);
+ PKIX_DECREF(client->currentRequest);
+ PKIX_DECREF(client->currentResponse);
+
+cleanup:
+
+ PKIX_DECREF(client);
+
+ PKIX_RETURN(CERTSTORE);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.h
new file mode 100644
index 000000000..4abe04328
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapdefaultclient.h
@@ -0,0 +1,82 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_ldapdefaultclient.h
+ *
+ * LDAPDefaultClient Object Type Definition
+ *
+ */
+
+#ifndef _PKIX_PL_LDAPDEFAULTCLIENT_H
+#define _PKIX_PL_LDAPDEFAULTCLIENT_H
+
+#include "pkix_pl_ldapt.h"
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * At the time of this version, there are unresolved questions about the LDAP
+ * protocol. Although RFC1777 describes a BIND and UNBIND message, it is not
+ * clear whether they are appropriate to this application. We have tested only
+ * using servers that do not expect authentication, and that reject BIND
+ * messages. It is not clear what values might be appropriate for the bindname
+ * and authentication fields, which are currently implemented as char strings
+ * supplied by the caller. (If this changes, the API and possibly the templates
+ * will have to change.) Therefore the LDAPClient_Create API contains a
+ * BindAPI structure, a union, which will have to be revised and extended when
+ * this area of the protocol is better understood.
+ *
+ */
+
+typedef enum {
+ CONNECT_PENDING,
+ CONNECTED,
+ BIND_PENDING,
+ BIND_RESPONSE,
+ BIND_RESPONSE_PENDING,
+ BOUND,
+ SEND_PENDING,
+ RECV,
+ RECV_PENDING,
+ RECV_INITIAL,
+ RECV_NONINITIAL,
+ ABANDON_PENDING
+} LdapClientConnectStatus;
+
+struct PKIX_PL_LdapDefaultClientStruct {
+ PKIX_PL_LdapClient vtable;
+ LdapClientConnectStatus connectStatus;
+ PKIX_UInt32 messageID;
+ PKIX_PL_HashTable *cachePtr;
+ PKIX_PL_Socket *clientSocket;
+ PRPollDesc pollDesc;
+ void *callbackList; /* cast this to (PKIX_PL_Socket_Callback *) */
+ LDAPBindAPI *bindAPI;
+ PLArenaPool *arena;
+ PRTime lastIO;
+ void *sendBuf;
+ PKIX_UInt32 bytesToWrite;
+ void *rcvBuf;
+ PKIX_UInt32 capacity;
+ void *currentInPtr;
+ PKIX_UInt32 currentBytesAvailable;
+ void *bindMsg;
+ PKIX_UInt32 bindMsgLen;
+ PKIX_List *entriesFound;
+ PKIX_PL_LdapRequest *currentRequest;
+ PKIX_PL_LdapResponse *currentResponse;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_LdapDefaultClient_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_LDAPDEFAULTCLIENT_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.c
new file mode 100644
index 000000000..4546e339a
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.c
@@ -0,0 +1,757 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_ldaprequest.c
+ *
+ */
+
+#include "pkix_pl_ldaprequest.h"
+
+/* --Private-LdapRequest-Functions------------------------------------- */
+
+/* Note: lengths do not include the NULL terminator */
+static const char caAttr[] = "caCertificate;binary";
+static unsigned int caAttrLen = sizeof(caAttr) - 1;
+static const char uAttr[] = "userCertificate;binary";
+static unsigned int uAttrLen = sizeof(uAttr) - 1;
+static const char ccpAttr[] = "crossCertificatePair;binary";
+static unsigned int ccpAttrLen = sizeof(ccpAttr) - 1;
+static const char crlAttr[] = "certificateRevocationList;binary";
+static unsigned int crlAttrLen = sizeof(crlAttr) - 1;
+static const char arlAttr[] = "authorityRevocationList;binary";
+static unsigned int arlAttrLen = sizeof(arlAttr) - 1;
+
+/*
+ * XXX If this function were moved into pkix_pl_ldapcertstore.c then all of
+ * LdapRequest and LdapResponse could be considered part of the LDAP client.
+ * But the constants, above, would have to be copied as well, and they are
+ * also needed in pkix_pl_LdapRequest_EncodeAttrs. So there would have to be
+ * two copies.
+ */
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_AttrTypeToBit
+ * DESCRIPTION:
+ *
+ * This function creates an attribute mask bit corresponding to the SECItem
+ * pointed to by "attrType", storing the result at "pAttrBit". The comparison
+ * is case-insensitive. If "attrType" does not match any of the known types,
+ * zero is stored at "pAttrBit".
+ *
+ * PARAMETERS
+ * "attrType"
+ * The address of the SECItem whose string contents are to be compared to
+ * the various known attribute types. Must be non-NULL.
+ * "pAttrBit"
+ * The address where the result is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an LdapRequest Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapRequest_AttrTypeToBit(
+ SECItem *attrType,
+ LdapAttrMask *pAttrBit,
+ void *plContext)
+{
+ LdapAttrMask attrBit = 0;
+ unsigned int attrLen = 0;
+ const char *s = NULL;
+
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_AttrTypeToBit");
+ PKIX_NULLCHECK_TWO(attrType, pAttrBit);
+
+ s = (const char *)attrType->data;
+ attrLen = attrType->len;
+
+ /*
+ * Taking note of the fact that all of the comparand strings are
+ * different lengths, we do a slight optimization. If a string
+ * length matches but the string does not match, we skip comparing
+ * to the other strings. If new strings are added to the comparand
+ * list, and any are of equal length, be careful to change the
+ * grouping of tests accordingly.
+ */
+ if (attrLen == caAttrLen) {
+ if (PORT_Strncasecmp(caAttr, s, attrLen) == 0) {
+ attrBit = LDAPATTR_CACERT;
+ }
+ } else if (attrLen == uAttrLen) {
+ if (PORT_Strncasecmp(uAttr, s, attrLen) == 0) {
+ attrBit = LDAPATTR_USERCERT;
+ }
+ } else if (attrLen == ccpAttrLen) {
+ if (PORT_Strncasecmp(ccpAttr, s, attrLen) == 0) {
+ attrBit = LDAPATTR_CROSSPAIRCERT;
+ }
+ } else if (attrLen == crlAttrLen) {
+ if (PORT_Strncasecmp(crlAttr, s, attrLen) == 0) {
+ attrBit = LDAPATTR_CERTREVLIST;
+ }
+ } else if (attrLen == arlAttrLen) {
+ if (PORT_Strncasecmp(arlAttr, s, attrLen) == 0) {
+ attrBit = LDAPATTR_AUTHREVLIST;
+ }
+ }
+
+ *pAttrBit = attrBit;
+
+ PKIX_RETURN(LDAPREQUEST);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_AttrStringToBit
+ * DESCRIPTION:
+ *
+ * This function creates an attribute mask bit corresponding to the null-
+ * terminated string pointed to by "attrString", storing the result at
+ * "pAttrBit". The comparison is case-insensitive. If "attrString" does not
+ * match any of the known types, zero is stored at "pAttrBit".
+ *
+ * PARAMETERS
+ * "attrString"
+ * The address of the null-terminated string whose contents are to be compared to
+ * the various known attribute types. Must be non-NULL.
+ * "pAttrBit"
+ * The address where the result is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an LdapRequest Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapRequest_AttrStringToBit(
+ char *attrString,
+ LdapAttrMask *pAttrBit,
+ void *plContext)
+{
+ LdapAttrMask attrBit = 0;
+ unsigned int attrLen = 0;
+
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_AttrStringToBit");
+ PKIX_NULLCHECK_TWO(attrString, pAttrBit);
+
+ attrLen = PL_strlen(attrString);
+
+ /*
+ * Taking note of the fact that all of the comparand strings are
+ * different lengths, we do a slight optimization. If a string
+ * length matches but the string does not match, we skip comparing
+ * to the other strings. If new strings are added to the comparand
+ * list, and any are of equal length, be careful to change the
+ * grouping of tests accordingly.
+ */
+ if (attrLen == caAttrLen) {
+ if (PORT_Strncasecmp(caAttr, attrString, attrLen) == 0) {
+ attrBit = LDAPATTR_CACERT;
+ }
+ } else if (attrLen == uAttrLen) {
+ if (PORT_Strncasecmp(uAttr, attrString, attrLen) == 0) {
+ attrBit = LDAPATTR_USERCERT;
+ }
+ } else if (attrLen == ccpAttrLen) {
+ if (PORT_Strncasecmp(ccpAttr, attrString, attrLen) == 0) {
+ attrBit = LDAPATTR_CROSSPAIRCERT;
+ }
+ } else if (attrLen == crlAttrLen) {
+ if (PORT_Strncasecmp(crlAttr, attrString, attrLen) == 0) {
+ attrBit = LDAPATTR_CERTREVLIST;
+ }
+ } else if (attrLen == arlAttrLen) {
+ if (PORT_Strncasecmp(arlAttr, attrString, attrLen) == 0) {
+ attrBit = LDAPATTR_AUTHREVLIST;
+ }
+ }
+
+ *pAttrBit = attrBit;
+
+ PKIX_RETURN(LDAPREQUEST);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_EncodeAttrs
+ * DESCRIPTION:
+ *
+ * This function obtains the attribute mask bits from the LdapRequest pointed
+ * to by "request", creates the corresponding array of AttributeTypes for the
+ * encoding of the SearchRequest message.
+ *
+ * PARAMETERS
+ * "request"
+ * The address of the LdapRequest whose attributes are to be encoded. Must
+ * be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an LdapRequest Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_LdapRequest_EncodeAttrs(
+ PKIX_PL_LdapRequest *request,
+ void *plContext)
+{
+ SECItem **attrArray = NULL;
+ PKIX_UInt32 attrIndex = 0;
+ LdapAttrMask attrBits;
+
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_EncodeAttrs");
+ PKIX_NULLCHECK_ONE(request);
+
+ /* construct "attrs" according to bits in request->attrBits */
+ attrBits = request->attrBits;
+ attrArray = request->attrArray;
+ if ((attrBits & LDAPATTR_CACERT) == LDAPATTR_CACERT) {
+ attrArray[attrIndex] = &(request->attributes[attrIndex]);
+ request->attributes[attrIndex].type = siAsciiString;
+ request->attributes[attrIndex].data = (unsigned char *)caAttr;
+ request->attributes[attrIndex].len = caAttrLen;
+ attrIndex++;
+ }
+ if ((attrBits & LDAPATTR_USERCERT) == LDAPATTR_USERCERT) {
+ attrArray[attrIndex] = &(request->attributes[attrIndex]);
+ request->attributes[attrIndex].type = siAsciiString;
+ request->attributes[attrIndex].data = (unsigned char *)uAttr;
+ request->attributes[attrIndex].len = uAttrLen;
+ attrIndex++;
+ }
+ if ((attrBits & LDAPATTR_CROSSPAIRCERT) == LDAPATTR_CROSSPAIRCERT) {
+ attrArray[attrIndex] = &(request->attributes[attrIndex]);
+ request->attributes[attrIndex].type = siAsciiString;
+ request->attributes[attrIndex].data = (unsigned char *)ccpAttr;
+ request->attributes[attrIndex].len = ccpAttrLen;
+ attrIndex++;
+ }
+ if ((attrBits & LDAPATTR_CERTREVLIST) == LDAPATTR_CERTREVLIST) {
+ attrArray[attrIndex] = &(request->attributes[attrIndex]);
+ request->attributes[attrIndex].type = siAsciiString;
+ request->attributes[attrIndex].data = (unsigned char *)crlAttr;
+ request->attributes[attrIndex].len = crlAttrLen;
+ attrIndex++;
+ }
+ if ((attrBits & LDAPATTR_AUTHREVLIST) == LDAPATTR_AUTHREVLIST) {
+ attrArray[attrIndex] = &(request->attributes[attrIndex]);
+ request->attributes[attrIndex].type = siAsciiString;
+ request->attributes[attrIndex].data = (unsigned char *)arlAttr;
+ request->attributes[attrIndex].len = arlAttrLen;
+ attrIndex++;
+ }
+ attrArray[attrIndex] = (SECItem *)NULL;
+
+ PKIX_RETURN(LDAPREQUEST);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapRequest_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_LDAPREQUEST_TYPE, plContext),
+ PKIX_OBJECTNOTLDAPREQUEST);
+
+ /*
+ * All dynamic fields in an LDAPRequest are allocated
+ * in an arena, and will be freed when the arena is destroyed.
+ */
+
+cleanup:
+
+ PKIX_RETURN(LDAPREQUEST);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapRequest_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_UInt32 dataLen = 0;
+ PKIX_UInt32 dindex = 0;
+ PKIX_UInt32 sizeOfLength = 0;
+ PKIX_UInt32 idLen = 0;
+ const unsigned char *msgBuf = NULL;
+ PKIX_PL_LdapRequest *ldapRq = NULL;
+
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_LDAPREQUEST_TYPE, plContext),
+ PKIX_OBJECTNOTLDAPREQUEST);
+
+ ldapRq = (PKIX_PL_LdapRequest *)object;
+
+ *pHashcode = 0;
+
+ /*
+ * Two requests that differ only in msgnum are a match! Therefore,
+ * start hashcoding beyond the encoded messageID field.
+ */
+ if (ldapRq->encoded) {
+ msgBuf = (const unsigned char *)ldapRq->encoded->data;
+ /* Is message length short form (one octet) or long form? */
+ if ((msgBuf[1] & 0x80) != 0) {
+ sizeOfLength = msgBuf[1] & 0x7F;
+ for (dindex = 0; dindex < sizeOfLength; dindex++) {
+ dataLen = (dataLen << 8) + msgBuf[dindex + 2];
+ }
+ } else {
+ dataLen = msgBuf[1];
+ }
+
+ /* How many bytes for the messageID? (Assume short form) */
+ idLen = msgBuf[dindex + 3] + 2;
+ dindex += idLen;
+ dataLen -= idLen;
+ msgBuf = &msgBuf[dindex + 2];
+
+ PKIX_CHECK(pkix_hash(msgBuf, dataLen, pHashcode, plContext),
+ PKIX_HASHFAILED);
+ }
+
+cleanup:
+
+ PKIX_RETURN(LDAPREQUEST);
+
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapRequest_Equals(
+ PKIX_PL_Object *firstObj,
+ PKIX_PL_Object *secondObj,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_PL_LdapRequest *firstReq = NULL;
+ PKIX_PL_LdapRequest *secondReq = NULL;
+ PKIX_UInt32 secondType = 0;
+ PKIX_UInt32 firstLen = 0;
+ const unsigned char *firstData = NULL;
+ const unsigned char *secondData = NULL;
+ PKIX_UInt32 sizeOfLength = 0;
+ PKIX_UInt32 dindex = 0;
+ PKIX_UInt32 i = 0;
+
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_Equals");
+ PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult);
+
+ /* test that firstObj is a LdapRequest */
+ PKIX_CHECK(pkix_CheckType(firstObj, PKIX_LDAPREQUEST_TYPE, plContext),
+ PKIX_FIRSTOBJARGUMENTNOTLDAPREQUEST);
+
+ /*
+ * Since we know firstObj is a LdapRequest, if both references are
+ * identical, they must be equal
+ */
+ if (firstObj == secondObj){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondObj isn't a LdapRequest, we don't throw an error.
+ * We simply return a Boolean result of FALSE
+ */
+ *pResult = PKIX_FALSE;
+ PKIX_CHECK(PKIX_PL_Object_GetType
+ (secondObj, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+ if (secondType != PKIX_LDAPREQUEST_TYPE) {
+ goto cleanup;
+ }
+
+ firstReq = (PKIX_PL_LdapRequest *)firstObj;
+ secondReq = (PKIX_PL_LdapRequest *)secondObj;
+
+ /* If either lacks an encoded string, they cannot be compared */
+ if (!(firstReq->encoded) || !(secondReq->encoded)) {
+ goto cleanup;
+ }
+
+ if (firstReq->encoded->len != secondReq->encoded->len) {
+ goto cleanup;
+ }
+
+ firstData = (const unsigned char *)firstReq->encoded->data;
+ secondData = (const unsigned char *)secondReq->encoded->data;
+
+ /*
+ * Two requests that differ only in msgnum are equal! Therefore,
+ * start the byte comparison beyond the encoded messageID field.
+ */
+
+ /* Is message length short form (one octet) or long form? */
+ if ((firstData[1] & 0x80) != 0) {
+ sizeOfLength = firstData[1] & 0x7F;
+ for (dindex = 0; dindex < sizeOfLength; dindex++) {
+ firstLen = (firstLen << 8) + firstData[dindex + 2];
+ }
+ } else {
+ firstLen = firstData[1];
+ }
+
+ /* How many bytes for the messageID? (Assume short form) */
+ i = firstData[dindex + 3] + 2;
+ dindex += i;
+ firstLen -= i;
+ firstData = &firstData[dindex + 2];
+
+ /*
+ * In theory, we have to calculate where the second message data
+ * begins by checking its length encodings. But if these messages
+ * are equal, we can re-use the calculation we already did. If they
+ * are not equal, the byte comparisons will surely fail.
+ */
+
+ secondData = &secondData[dindex + 2];
+
+ for (i = 0; i < firstLen; i++) {
+ if (firstData[i] != secondData[i]) {
+ goto cleanup;
+ }
+ }
+
+ *pResult = PKIX_TRUE;
+
+cleanup:
+
+ PKIX_RETURN(LDAPREQUEST);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_LDAPREQUEST_TYPE and its related functions with
+ * systemClasses[]
+ * PARAMETERS:
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_LdapRequest_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_RegisterSelf");
+
+ entry.description = "LdapRequest";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_LdapRequest);
+ entry.destructor = pkix_pl_LdapRequest_Destroy;
+ entry.equalsFunction = pkix_pl_LdapRequest_Equals;
+ entry.hashcodeFunction = pkix_pl_LdapRequest_Hashcode;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_LDAPREQUEST_TYPE] = entry;
+
+ PKIX_RETURN(LDAPREQUEST);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_Create
+ * DESCRIPTION:
+ *
+ * This function creates an LdapRequest using the PLArenaPool pointed to by
+ * "arena", a message number whose value is "msgnum", a base object pointed to
+ * by "issuerDN", a scope whose value is "scope", a derefAliases flag whose
+ * value is "derefAliases", a sizeLimit whose value is "sizeLimit", a timeLimit
+ * whose value is "timeLimit", an attrsOnly flag whose value is "attrsOnly", a
+ * filter whose value is "filter", and attribute bits whose value is
+ * "attrBits"; storing the result at "pRequestMsg".
+ *
+ * See pkix_pl_ldaptemplates.c (and below) for the ASN.1 representation of
+ * message components, and see pkix_pl_ldapt.h for data types.
+ *
+ * PARAMETERS
+ * "arena"
+ * The address of the PLArenaPool to be used in the encoding. Must be
+ * non-NULL.
+ * "msgnum"
+ * The UInt32 message number to be used for the messageID component of the
+ * LDAP message exchange.
+ * "issuerDN"
+ * The address of the string to be used for the baseObject component of the
+ * LDAP SearchRequest message. Must be non-NULL.
+ * "scope"
+ * The (enumerated) ScopeType to be used for the scope component of the
+ * LDAP SearchRequest message
+ * "derefAliases"
+ * The (enumerated) DerefType to be used for the derefAliases component of
+ * the LDAP SearchRequest message
+ * "sizeLimit"
+ * The UInt32 value to be used for the sizeLimit component of the LDAP
+ * SearchRequest message
+ * "timeLimit"
+ * The UInt32 value to be used for the timeLimit component of the LDAP
+ * SearchRequest message
+ * "attrsOnly"
+ * The Boolean value to be used for the attrsOnly component of the LDAP
+ * SearchRequest message
+ * "filter"
+ * The filter to be used for the filter component of the LDAP
+ * SearchRequest message
+ * "attrBits"
+ * The LdapAttrMask bits indicating the attributes to be included in the
+ * attributes sequence of the LDAP SearchRequest message
+ * "pRequestMsg"
+ * The address at which the address of the LdapRequest is stored. Must
+ * be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an LdapRequest Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+/*
+ * SearchRequest ::=
+ * [APPLICATION 3] SEQUENCE {
+ * baseObject LDAPDN,
+ * scope ENUMERATED {
+ * baseObject (0),
+ * singleLevel (1),
+ * wholeSubtree (2)
+ * },
+ * derefAliases ENUMERATED {
+ * neverDerefAliases (0),
+ * derefInSearching (1),
+ * derefFindingBaseObj (2),
+ * alwaysDerefAliases (3)
+ * },
+ * sizeLimit INTEGER (0 .. MAXINT),
+ * -- value of 0 implies no sizeLimit
+ * timeLimit INTEGER (0 .. MAXINT),
+ * -- value of 0 implies no timeLimit
+ * attrsOnly BOOLEAN,
+ * -- TRUE, if only attributes (without values)
+ * -- to be returned
+ * filter Filter,
+ * attributes SEQUENCE OF AttributeType
+ * }
+ *
+ * Filter ::=
+ * CHOICE {
+ * and [0] SET OF Filter,
+ * or [1] SET OF Filter,
+ * not [2] Filter,
+ * equalityMatch [3] AttributeValueAssertion,
+ * substrings [4] SubstringFilter,
+ * greaterOrEqual [5] AttributeValueAssertion,
+ * lessOrEqual [6] AttributeValueAssertion,
+ * present [7] AttributeType,
+ * approxMatch [8] AttributeValueAssertion
+ * }
+ *
+ * SubstringFilter ::=
+ * SEQUENCE {
+ * type AttributeType,
+ * SEQUENCE OF CHOICE {
+ * initial [0] LDAPString,
+ * any [1] LDAPString,
+ * final [2] LDAPString,
+ * }
+ * }
+ *
+ * AttributeValueAssertion ::=
+ * SEQUENCE {
+ * attributeType AttributeType,
+ * attributeValue AttributeValue,
+ * }
+ *
+ * AttributeValue ::= OCTET STRING
+ *
+ * AttributeType ::= LDAPString
+ * -- text name of the attribute, or dotted
+ * -- OID representation
+ *
+ * LDAPDN ::= LDAPString
+ *
+ * LDAPString ::= OCTET STRING
+ *
+ */
+PKIX_Error *
+pkix_pl_LdapRequest_Create(
+ PLArenaPool *arena,
+ PKIX_UInt32 msgnum,
+ char *issuerDN,
+ ScopeType scope,
+ DerefType derefAliases,
+ PKIX_UInt32 sizeLimit,
+ PKIX_UInt32 timeLimit,
+ char attrsOnly,
+ LDAPFilter *filter,
+ LdapAttrMask attrBits,
+ PKIX_PL_LdapRequest **pRequestMsg,
+ void *plContext)
+{
+ LDAPMessage msg;
+ LDAPSearch *search;
+ PKIX_PL_LdapRequest *ldapRequest = NULL;
+ char scopeTypeAsChar;
+ char derefAliasesTypeAsChar;
+ SECItem *attrArray[MAX_LDAPATTRS + 1];
+
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_Create");
+ PKIX_NULLCHECK_THREE(arena, issuerDN, pRequestMsg);
+
+ /* create a PKIX_PL_LdapRequest object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_LDAPREQUEST_TYPE,
+ sizeof (PKIX_PL_LdapRequest),
+ (PKIX_PL_Object **)&ldapRequest,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ ldapRequest->arena = arena;
+ ldapRequest->msgnum = msgnum;
+ ldapRequest->issuerDN = issuerDN;
+ ldapRequest->scope = scope;
+ ldapRequest->derefAliases = derefAliases;
+ ldapRequest->sizeLimit = sizeLimit;
+ ldapRequest->timeLimit = timeLimit;
+ ldapRequest->attrsOnly = attrsOnly;
+ ldapRequest->filter = filter;
+ ldapRequest->attrBits = attrBits;
+
+ ldapRequest->attrArray = attrArray;
+
+ PKIX_CHECK(pkix_pl_LdapRequest_EncodeAttrs
+ (ldapRequest, plContext),
+ PKIX_LDAPREQUESTENCODEATTRSFAILED);
+
+ PKIX_PL_NSSCALL
+ (LDAPREQUEST, PORT_Memset, (&msg, 0, sizeof (LDAPMessage)));
+
+ msg.messageID.type = siUnsignedInteger;
+ msg.messageID.data = (void*)&msgnum;
+ msg.messageID.len = sizeof (msgnum);
+
+ msg.protocolOp.selector = LDAP_SEARCH_TYPE;
+
+ search = &(msg.protocolOp.op.searchMsg);
+
+ search->baseObject.type = siAsciiString;
+ search->baseObject.data = (void *)issuerDN;
+ search->baseObject.len = PL_strlen(issuerDN);
+ scopeTypeAsChar = (char)scope;
+ search->scope.type = siUnsignedInteger;
+ search->scope.data = (void *)&scopeTypeAsChar;
+ search->scope.len = sizeof (scopeTypeAsChar);
+ derefAliasesTypeAsChar = (char)derefAliases;
+ search->derefAliases.type = siUnsignedInteger;
+ search->derefAliases.data =
+ (void *)&derefAliasesTypeAsChar;
+ search->derefAliases.len =
+ sizeof (derefAliasesTypeAsChar);
+ search->sizeLimit.type = siUnsignedInteger;
+ search->sizeLimit.data = (void *)&sizeLimit;
+ search->sizeLimit.len = sizeof (PKIX_UInt32);
+ search->timeLimit.type = siUnsignedInteger;
+ search->timeLimit.data = (void *)&timeLimit;
+ search->timeLimit.len = sizeof (PKIX_UInt32);
+ search->attrsOnly.type = siBuffer;
+ search->attrsOnly.data = (void *)&attrsOnly;
+ search->attrsOnly.len = sizeof (attrsOnly);
+
+ PKIX_PL_NSSCALL
+ (LDAPREQUEST,
+ PORT_Memcpy,
+ (&search->filter, filter, sizeof (LDAPFilter)));
+
+ search->attributes = attrArray;
+
+ PKIX_PL_NSSCALLRV
+ (LDAPREQUEST, ldapRequest->encoded, SEC_ASN1EncodeItem,
+ (arena, NULL, (void *)&msg, PKIX_PL_LDAPMessageTemplate));
+
+ if (!(ldapRequest->encoded)) {
+ PKIX_ERROR(PKIX_FAILEDINENCODINGSEARCHREQUEST);
+ }
+
+ *pRequestMsg = ldapRequest;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(ldapRequest);
+ }
+
+ PKIX_RETURN(LDAPREQUEST);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapRequest_GetEncoded
+ * DESCRIPTION:
+ *
+ * This function obtains the encoded message from the LdapRequest pointed to
+ * by "request", storing the result at "pRequestBuf".
+ *
+ * PARAMETERS
+ * "request"
+ * The address of the LdapRequest whose encoded message is to be
+ * retrieved. Must be non-NULL.
+ * "pRequestBuf"
+ * The address at which is stored the address of the encoded message. Must
+ * be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an LdapRequest Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapRequest_GetEncoded(
+ PKIX_PL_LdapRequest *request,
+ SECItem **pRequestBuf,
+ void *plContext)
+{
+ PKIX_ENTER(LDAPREQUEST, "pkix_pl_LdapRequest_GetEncoded");
+ PKIX_NULLCHECK_TWO(request, pRequestBuf);
+
+ *pRequestBuf = request->encoded;
+
+ PKIX_RETURN(LDAPREQUEST);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.h
new file mode 100644
index 000000000..1d05a9447
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaprequest.h
@@ -0,0 +1,86 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_ldaprequest.h
+ *
+ * LdapRequest Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_LDAPREQUEST_H
+#define _PKIX_PL_LDAPREQUEST_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ USER_CERT,
+ CA_CERT,
+ CROSS_CERT,
+ CRL,
+ ARL,
+ DELTA_CRL
+} PKIX_PL_LdapAttr;
+
+struct PKIX_PL_LdapRequestStruct{
+ PLArenaPool *arena;
+ PKIX_UInt32 msgnum;
+ char *issuerDN;
+ ScopeType scope;
+ DerefType derefAliases;
+ PKIX_UInt32 sizeLimit;
+ PKIX_UInt32 timeLimit;
+ char attrsOnly;
+ LDAPFilter *filter;
+ LdapAttrMask attrBits;
+ SECItem attributes[MAX_LDAPATTRS];
+ SECItem **attrArray;
+ SECItem *encoded;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_pl_LdapRequest_Create(
+ PLArenaPool *arena,
+ PKIX_UInt32 msgnum,
+ char *issuerDN,
+ ScopeType scope,
+ DerefType derefAliases,
+ PKIX_UInt32 sizeLimit,
+ PKIX_UInt32 timeLimit,
+ char attrsOnly,
+ LDAPFilter *filter,
+ LdapAttrMask attrBits,
+ PKIX_PL_LdapRequest **pRequestMsg,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapRequest_AttrTypeToBit(
+ SECItem *attrType,
+ LdapAttrMask *pAttrBit,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapRequest_AttrStringToBit(
+ char *attrString,
+ LdapAttrMask *pAttrBit,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapRequest_GetEncoded(
+ PKIX_PL_LdapRequest *request,
+ SECItem **pRequestBuf,
+ void *plContext);
+
+PKIX_Error *pkix_pl_LdapRequest_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_LDAPREQUEST_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.c
new file mode 100644
index 000000000..cd2543f3b
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.c
@@ -0,0 +1,786 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_ldapresponse.c
+ *
+ */
+
+#include <fcntl.h>
+#include "pkix_pl_ldapresponse.h"
+
+/* --Private-LdapResponse-Functions------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapResponse_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_LdapResponse *ldapRsp = NULL;
+ LDAPMessage *m = NULL;
+ LDAPSearchResponseEntry *entry = NULL;
+ LDAPSearchResponseResult *result = NULL;
+ LDAPSearchResponseAttr **attributes = NULL;
+ LDAPSearchResponseAttr *attr = NULL;
+ SECItem **valp = NULL;
+ SECItem *val = NULL;
+
+ PKIX_ENTER(LDAPRESPONSE, "pkix_pl_LdapResponse_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_LDAPRESPONSE_TYPE, plContext),
+ PKIX_OBJECTNOTLDAPRESPONSE);
+
+ ldapRsp = (PKIX_PL_LdapResponse *)object;
+
+ m = &ldapRsp->decoded;
+
+ if (m->messageID.data != NULL) {
+ PR_Free(m->messageID.data);
+ }
+
+ if (m->protocolOp.selector ==
+ LDAP_SEARCHRESPONSEENTRY_TYPE) {
+ entry = &m->protocolOp.op.searchResponseEntryMsg;
+ if (entry->objectName.data != NULL) {
+ PR_Free(entry->objectName.data);
+ }
+ if (entry->attributes != NULL) {
+ for (attributes = entry->attributes;
+ *attributes != NULL;
+ attributes++) {
+ attr = *attributes;
+ PR_Free(attr->attrType.data);
+ for (valp = attr->val; *valp != NULL; valp++) {
+ val = *valp;
+ if (val->data != NULL) {
+ PR_Free(val->data);
+ }
+ PR_Free(val);
+ }
+ PR_Free(attr->val);
+ PR_Free(attr);
+ }
+ PR_Free(entry->attributes);
+ }
+ } else if (m->protocolOp.selector ==
+ LDAP_SEARCHRESPONSERESULT_TYPE) {
+ result = &m->protocolOp.op.searchResponseResultMsg;
+ if (result->resultCode.data != NULL) {
+ PR_Free(result->resultCode.data);
+ }
+ }
+
+ PKIX_FREE(ldapRsp->derEncoded.data);
+
+cleanup:
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapResponse_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_UInt32 dataLen = 0;
+ PKIX_UInt32 dindex = 0;
+ PKIX_UInt32 sizeOfLength = 0;
+ PKIX_UInt32 idLen = 0;
+ const unsigned char *msgBuf = NULL;
+ PKIX_PL_LdapResponse *ldapRsp = NULL;
+
+ PKIX_ENTER(LDAPRESPONSE, "pkix_pl_LdapResponse_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_LDAPRESPONSE_TYPE, plContext),
+ PKIX_OBJECTNOTLDAPRESPONSE);
+
+ ldapRsp = (PKIX_PL_LdapResponse *)object;
+
+ *pHashcode = 0;
+
+ /*
+ * Two responses that differ only in msgnum are a match! Therefore,
+ * start hashcoding beyond the encoded messageID field.
+ */
+ if (ldapRsp->derEncoded.data) {
+ msgBuf = (const unsigned char *)ldapRsp->derEncoded.data;
+ /* Is message length short form (one octet) or long form? */
+ if ((msgBuf[1] & 0x80) != 0) {
+ sizeOfLength = msgBuf[1] & 0x7F;
+ for (dindex = 0; dindex < sizeOfLength; dindex++) {
+ dataLen = (dataLen << 8) + msgBuf[dindex + 2];
+ }
+ } else {
+ dataLen = msgBuf[1];
+ }
+
+ /* How many bytes for the messageID? (Assume short form) */
+ idLen = msgBuf[dindex + 3] + 2;
+ dindex += idLen;
+ dataLen -= idLen;
+ msgBuf = &msgBuf[dindex + 2];
+
+ PKIX_CHECK(pkix_hash(msgBuf, dataLen, pHashcode, plContext),
+ PKIX_HASHFAILED);
+ }
+
+cleanup:
+
+ PKIX_RETURN(LDAPRESPONSE);
+
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_LdapResponse_Equals(
+ PKIX_PL_Object *firstObj,
+ PKIX_PL_Object *secondObj,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_PL_LdapResponse *rsp1 = NULL;
+ PKIX_PL_LdapResponse *rsp2 = NULL;
+ PKIX_UInt32 secondType = 0;
+ PKIX_UInt32 firstLen = 0;
+ const unsigned char *firstData = NULL;
+ const unsigned char *secondData = NULL;
+ PKIX_UInt32 sizeOfLength = 0;
+ PKIX_UInt32 dindex = 0;
+ PKIX_UInt32 i = 0;
+
+ PKIX_ENTER(LDAPRESPONSE, "pkix_pl_LdapResponse_Equals");
+ PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult);
+
+ /* test that firstObj is a LdapResponse */
+ PKIX_CHECK(pkix_CheckType(firstObj, PKIX_LDAPRESPONSE_TYPE, plContext),
+ PKIX_FIRSTOBJARGUMENTNOTLDAPRESPONSE);
+
+ /*
+ * Since we know firstObj is a LdapResponse, if both references are
+ * identical, they must be equal
+ */
+ if (firstObj == secondObj){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondObj isn't a LdapResponse, we don't throw an error.
+ * We simply return a Boolean result of FALSE
+ */
+ *pResult = PKIX_FALSE;
+ PKIX_CHECK(PKIX_PL_Object_GetType(secondObj, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+ if (secondType != PKIX_LDAPRESPONSE_TYPE) {
+ goto cleanup;
+ }
+
+ rsp1 = (PKIX_PL_LdapResponse *)firstObj;
+ rsp2 = (PKIX_PL_LdapResponse *)secondObj;
+
+ /* If either lacks an encoded string, they cannot be compared */
+ if (!(rsp1->derEncoded.data) || !(rsp2->derEncoded.data)) {
+ goto cleanup;
+ }
+
+ if (rsp1->derEncoded.len != rsp2->derEncoded.len) {
+ goto cleanup;
+ }
+
+ firstData = (const unsigned char *)rsp1->derEncoded.data;
+ secondData = (const unsigned char *)rsp2->derEncoded.data;
+
+ /*
+ * Two responses that differ only in msgnum are equal! Therefore,
+ * start the byte comparison beyond the encoded messageID field.
+ */
+
+ /* Is message length short form (one octet) or long form? */
+ if ((firstData[1] & 0x80) != 0) {
+ sizeOfLength = firstData[1] & 0x7F;
+ for (dindex = 0; dindex < sizeOfLength; dindex++) {
+ firstLen = (firstLen << 8) + firstData[dindex + 2];
+ }
+ } else {
+ firstLen = firstData[1];
+ }
+
+ /* How many bytes for the messageID? (Assume short form) */
+ i = firstData[dindex + 3] + 2;
+ dindex += i;
+ firstLen -= i;
+ firstData = &firstData[dindex + 2];
+
+ /*
+ * In theory, we have to calculate where the second message data
+ * begins by checking its length encodings. But if these messages
+ * are equal, we can re-use the calculation we already did. If they
+ * are not equal, the byte comparisons will surely fail.
+ */
+
+ secondData = &secondData[dindex + 2];
+
+ for (i = 0; i < firstLen; i++) {
+ if (firstData[i] != secondData[i]) {
+ goto cleanup;
+ }
+ }
+
+ *pResult = PKIX_TRUE;
+
+cleanup:
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_LDAPRESPONSE_TYPE and its related functions with
+ * systemClasses[]
+ * PARAMETERS:
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_LdapResponse_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(LDAPRESPONSE, "pkix_pl_LdapResponse_RegisterSelf");
+
+ entry.description = "LdapResponse";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_LdapResponse);
+ entry.destructor = pkix_pl_LdapResponse_Destroy;
+ entry.equalsFunction = pkix_pl_LdapResponse_Equals;
+ entry.hashcodeFunction = pkix_pl_LdapResponse_Hashcode;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_LDAPRESPONSE_TYPE] = entry;
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_Create
+ * DESCRIPTION:
+ *
+ * This function creates an LdapResponse for the LDAPMessageType provided in
+ * "responseType" and a buffer capacity provided by "totalLength". It copies
+ * into its buffer either "totalLength" or "bytesAvailable" bytes, whichever
+ * is less, from the buffer pointed to by "partialData", storing the number of
+ * bytes copied at "pBytesConsumed" and storing the address of the LdapResponse
+ * at "pLdapResponse".
+ *
+ * If a message is complete in a single I/O buffer, the LdapResponse will be
+ * complete when this function returns. If the message carries over into
+ * additional buffers, their contents will be added to the LdapResponse by
+ * susequent calls to pkix_pl_LdapResponse_Append.
+ *
+ * PARAMETERS
+ * "responseType"
+ * The value of the message type (LDAP_SEARCHRESPONSEENTRY_TYPE or
+ * LDAP_SEARCHRESPONSERESULT_TYPE) for the LdapResponse being created
+ * "totalLength"
+ * The UInt32 value for the total length of the encoded message to be
+ * stored in the LdapResponse
+ * "bytesAvailable"
+ * The UInt32 value for the number of bytes of data available in the
+ * current buffer.
+ * "partialData"
+ * The address from which data is to be copied.
+ * "pBytesConsumed"
+ * The address at which is stored the UInt32 number of bytes taken from the
+ * current buffer. If this number is less than "bytesAvailable", then bytes
+ * remain in the buffer for the next LdapResponse. Must be non-NULL.
+ * "pLdapResponse"
+ * The address where the created LdapResponse is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an LdapResponse Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapResponse_Create(
+ LDAPMessageType responseType,
+ PKIX_UInt32 totalLength,
+ PKIX_UInt32 bytesAvailable,
+ void *partialData,
+ PKIX_UInt32 *pBytesConsumed,
+ PKIX_PL_LdapResponse **pLdapResponse,
+ void *plContext)
+{
+ PKIX_UInt32 bytesConsumed = 0;
+ PKIX_PL_LdapResponse *ldapResponse = NULL;
+ void *data = NULL;
+
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_Create");
+ PKIX_NULLCHECK_ONE(pLdapResponse);
+
+ if (bytesAvailable <= totalLength) {
+ bytesConsumed = bytesAvailable;
+ } else {
+ bytesConsumed = totalLength;
+ }
+
+ /* create a PKIX_PL_LdapResponse object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_LDAPRESPONSE_TYPE,
+ sizeof (PKIX_PL_LdapResponse),
+ (PKIX_PL_Object **)&ldapResponse,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ ldapResponse->decoded.protocolOp.selector = responseType;
+ ldapResponse->totalLength = totalLength;
+ ldapResponse->partialLength = bytesConsumed;
+
+ if (totalLength != 0){
+ /* Alloc space for array */
+ PKIX_NULLCHECK_ONE(partialData);
+
+ PKIX_CHECK(PKIX_PL_Malloc
+ (totalLength,
+ &data,
+ plContext),
+ PKIX_MALLOCFAILED);
+
+ PKIX_PL_NSSCALL
+ (LDAPRESPONSE,
+ PORT_Memcpy,
+ (data, partialData, bytesConsumed));
+ }
+
+ ldapResponse->derEncoded.type = siBuffer;
+ ldapResponse->derEncoded.data = data;
+ ldapResponse->derEncoded.len = totalLength;
+ *pBytesConsumed = bytesConsumed;
+ *pLdapResponse = ldapResponse;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(ldapResponse);
+ }
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_Append
+ * DESCRIPTION:
+ *
+ * This function updates the LdapResponse pointed to by "response" with up to
+ * "incrLength" from the buffer pointer to by "incrData", storing the number of
+ * bytes copied at "pBytesConsumed".
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the LdapResponse being updated. Must be non-zero.
+ * "incrLength"
+ * The UInt32 value for the number of bytes of data available in the
+ * current buffer.
+ * "incrData"
+ * The address from which data is to be copied.
+ * "pBytesConsumed"
+ * The address at which is stored the UInt32 number of bytes taken from the
+ * current buffer. If this number is less than "incrLength", then bytes
+ * remain in the buffer for the next LdapResponse. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an LdapResponse Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapResponse_Append(
+ PKIX_PL_LdapResponse *response,
+ PKIX_UInt32 incrLength,
+ void *incrData,
+ PKIX_UInt32 *pBytesConsumed,
+ void *plContext)
+{
+ PKIX_UInt32 newPartialLength = 0;
+ PKIX_UInt32 bytesConsumed = 0;
+ void *dest = NULL;
+
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_Append");
+ PKIX_NULLCHECK_TWO(response, pBytesConsumed);
+
+ if (incrLength > 0) {
+
+ /* Calculate how many bytes we have room for. */
+ bytesConsumed =
+ response->totalLength - response->partialLength;
+
+ if (bytesConsumed > incrLength) {
+ bytesConsumed = incrLength;
+ }
+
+ newPartialLength = response->partialLength + bytesConsumed;
+
+ PKIX_NULLCHECK_ONE(incrData);
+
+ dest = &(((char *)response->derEncoded.data)[
+ response->partialLength]);
+
+ PKIX_PL_NSSCALL
+ (LDAPRESPONSE,
+ PORT_Memcpy,
+ (dest, incrData, bytesConsumed));
+
+ response->partialLength = newPartialLength;
+ }
+
+ *pBytesConsumed = bytesConsumed;
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_IsComplete
+ * DESCRIPTION:
+ *
+ * This function determines whether the LdapResponse pointed to by "response"
+ * contains all the data called for by the "totalLength" parameter provided
+ * when it was created, storing PKIX_TRUE at "pIsComplete" if so, and
+ * PKIX_FALSE otherwise.
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the LdapResponse being evaluaTED. Must be non-zero.
+ * "incrLength"
+ * The UInt32 value for the number of bytes of data available in the
+ * current buffer.
+ * "incrData"
+ * The address from which data is to be copied.
+ * "pIsComplete"
+ * The address at which is stored the Boolean indication of whether the
+ * LdapResponse is complete. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an LdapResponse Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapResponse_IsComplete(
+ PKIX_PL_LdapResponse *response,
+ PKIX_Boolean *pIsComplete,
+ void *plContext)
+{
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_IsComplete");
+ PKIX_NULLCHECK_TWO(response, pIsComplete);
+
+ if (response->totalLength == response->partialLength) {
+ *pIsComplete = PKIX_TRUE;
+ } else {
+ *pIsComplete = PKIX_FALSE;
+ }
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_Decode
+ * DESCRIPTION:
+ *
+ * This function decodes the DER data contained in the LdapResponse pointed to
+ * by "response", using the arena pointed to by "arena", and storing at
+ * "pStatus" SECSuccess if the decoding was successful and SECFailure
+ * otherwise. The decoded message is stored in an element of "response".
+ *
+ * PARAMETERS
+ * "arena"
+ * The address of the PLArenaPool to be used in the decoding. Must be
+ * non-NULL.
+ * "response"
+ * The address of the LdapResponse whose DER data is to be decoded. Must
+ * be non-NULL.
+ * "pStatus"
+ * The address at which is stored the status from the decoding, SECSuccess
+ * if successful, SECFailure otherwise. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an LdapResponse Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapResponse_Decode(
+ PLArenaPool *arena,
+ PKIX_PL_LdapResponse *response,
+ SECStatus *pStatus,
+ void *plContext)
+{
+ LDAPMessage *msg;
+ SECStatus rv = SECFailure;
+
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_Decode");
+ PKIX_NULLCHECK_THREE(arena, response, pStatus);
+
+ if (response->totalLength != response->partialLength) {
+ PKIX_ERROR(PKIX_ATTEMPTTODECODEANINCOMPLETERESPONSE);
+ }
+
+ msg = &(response->decoded);
+
+ PKIX_PL_NSSCALL
+ (LDAPRESPONSE, PORT_Memset, (msg, 0, sizeof (LDAPMessage)));
+
+ PKIX_PL_NSSCALLRV(LDAPRESPONSE, rv, SEC_ASN1DecodeItem,
+ (NULL, msg, PKIX_PL_LDAPMessageTemplate, &(response->derEncoded)));
+
+ *pStatus = rv;
+cleanup:
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_GetMessage
+ * DESCRIPTION:
+ *
+ * This function obtains the decoded message from the LdapResponse pointed to
+ * by "response", storing the result at "pMessage".
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the LdapResponse whose decoded message is to be
+ * retrieved. Must be non-NULL.
+ * "pMessage"
+ * The address at which is stored the address of the decoded message. Must
+ * be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapResponse_GetMessage(
+ PKIX_PL_LdapResponse *response,
+ LDAPMessage **pMessage,
+ void *plContext)
+{
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetMessage");
+ PKIX_NULLCHECK_TWO(response, pMessage);
+
+ *pMessage = &response->decoded;
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_GetCapacity
+ * DESCRIPTION:
+ *
+ * This function obtains from the LdapResponse pointed to by "response" the
+ * number of bytes remaining to be read, based on the totalLength that was
+ * provided to LdapResponse_Create and the data subsequently provided to
+ * LdapResponse_Append, storing the result at "pMessage".
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the LdapResponse whose remaining capacity is to be
+ * retrieved. Must be non-NULL.
+ * "pCapacity"
+ * The address at which is stored the address of the decoded message. Must
+ * be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an LdapResponse Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapResponse_GetCapacity(
+ PKIX_PL_LdapResponse *response,
+ PKIX_UInt32 *pCapacity,
+ void *plContext)
+{
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetCapacity");
+ PKIX_NULLCHECK_TWO(response, pCapacity);
+
+ *pCapacity = response->totalLength - response->partialLength;
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_GetMessageType
+ * DESCRIPTION:
+ *
+ * This function obtains the message type from the LdapResponse pointed to
+ * by "response", storing the result at "pMessageType".
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the LdapResponse whose message type is to be
+ * retrieved. Must be non-NULL.
+ * "pMessageType"
+ * The address at which is stored the type of the response message. Must
+ * be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapResponse_GetMessageType(
+ PKIX_PL_LdapResponse *response,
+ LDAPMessageType *pMessageType,
+ void *plContext)
+{
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetMessageType");
+ PKIX_NULLCHECK_TWO(response, pMessageType);
+
+ *pMessageType = response->decoded.protocolOp.selector;
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_GetResultCode
+ * DESCRIPTION:
+ *
+ * This function obtains the result code from the LdapResponse pointed to
+ * by "response", storing the result at "pResultCode".
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the LdapResponse whose result code is to be
+ * retrieved. Must be non-NULL.
+ * "pResultCode"
+ * The address at which is stored the address of the decoded message. Must
+ * be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an LdapResponse Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapResponse_GetResultCode(
+ PKIX_PL_LdapResponse *response,
+ LDAPResultCode *pResultCode,
+ void *plContext)
+{
+ LDAPMessageType messageType = 0;
+ LDAPSearchResponseResult *resultMsg = NULL;
+
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetResultCode");
+ PKIX_NULLCHECK_TWO(response, pResultCode);
+
+ messageType = response->decoded.protocolOp.selector;
+
+ if (messageType != LDAP_SEARCHRESPONSERESULT_TYPE) {
+ PKIX_ERROR(PKIX_GETRESULTCODECALLEDFORNONRESULTMESSAGE);
+ }
+
+ resultMsg = &response->decoded.protocolOp.op.searchResponseResultMsg;
+
+ *pResultCode = *(resultMsg->resultCode.data);
+
+cleanup:
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_LdapResponse_GetAttributes
+ * DESCRIPTION:
+ *
+ * This function obtains the attributes from the LdapResponse pointed to
+ * by "response", storing the result at "pAttributes".
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the LdapResponse whose decoded message is to be
+ * retrieved. Must be non-NULL.
+ * "pAttributes"
+ * The address at which is stored the attributes of the message. Must be
+ * non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an LdapResponse Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_LdapResponse_GetAttributes(
+ PKIX_PL_LdapResponse *response,
+ LDAPSearchResponseAttr ***pAttributes,
+ void *plContext)
+{
+ LDAPMessageType messageType = 0;
+
+ PKIX_ENTER(LDAPRESPONSE, "PKIX_PL_LdapResponse_GetResultCode");
+ PKIX_NULLCHECK_TWO(response, pAttributes);
+
+ messageType = response->decoded.protocolOp.selector;
+
+ if (messageType != LDAP_SEARCHRESPONSEENTRY_TYPE) {
+ PKIX_ERROR(PKIX_GETATTRIBUTESCALLEDFORNONENTRYMESSAGE);
+ }
+
+ *pAttributes = response->
+ decoded.protocolOp.op.searchResponseEntryMsg.attributes;
+
+cleanup:
+
+ PKIX_RETURN(LDAPRESPONSE);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.h
new file mode 100644
index 000000000..37dc916b1
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapresponse.h
@@ -0,0 +1,96 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_ldapresponse.h
+ *
+ * LdapResponse Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_LDAPRESPONSE_H
+#define _PKIX_PL_LDAPRESPONSE_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_LdapResponseStruct{
+ LDAPMessage decoded;
+ PKIX_UInt32 partialLength;
+ PKIX_UInt32 totalLength;
+ SECItem derEncoded;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_pl_LdapResponse_Create(
+ LDAPMessageType responseType,
+ PKIX_UInt32 totalLength,
+ PKIX_UInt32 bytesAvailable,
+ void *partialData,
+ PKIX_UInt32 *pBytesConsumed,
+ PKIX_PL_LdapResponse **pResponse,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapResponse_Append(
+ PKIX_PL_LdapResponse *response,
+ PKIX_UInt32 partialLength,
+ void *partialData,
+ PKIX_UInt32 *bytesConsumed,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapResponse_IsComplete(
+ PKIX_PL_LdapResponse *response,
+ PKIX_Boolean *pIsComplete,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapResponse_Decode(
+ PLArenaPool *arena,
+ PKIX_PL_LdapResponse *response,
+ SECStatus *pStatus,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapResponse_GetMessage(
+ PKIX_PL_LdapResponse *response,
+ LDAPMessage **pMessage,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapResponse_GetMessageType(
+ PKIX_PL_LdapResponse *response,
+ LDAPMessageType *pMessageType,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapResponse_GetCapacity(
+ PKIX_PL_LdapResponse *response,
+ PKIX_UInt32 *pCapacity,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapResponse_GetResultCode(
+ PKIX_PL_LdapResponse *response,
+ LDAPResultCode *pResultCode,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_LdapResponse_GetAttributes(
+ PKIX_PL_LdapResponse *response,
+ LDAPSearchResponseAttr ***pAttributes,
+ void *plContext);
+
+PKIX_Error *pkix_pl_LdapResponse_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_LDAPRESPONSE_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapt.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapt.h
new file mode 100644
index 000000000..539803638
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldapt.h
@@ -0,0 +1,314 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#ifndef _LDAP_H_
+#define _LDAP_H_
+
+#include "certt.h"
+#include "pkixt.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern const SEC_ASN1Template PKIX_PL_LDAPCrossCertPairTemplate[];
+SEC_ASN1_CHOOSER_DECLARE(PKIX_PL_LDAPCrossCertPairTemplate)
+extern const SEC_ASN1Template PKIX_PL_LDAPMessageTemplate[];
+SEC_ASN1_CHOOSER_DECLARE(PKIX_PL_LDAPMessageTemplate)
+extern const SEC_ASN1Template LDAPFilterTemplate[];
+SEC_ASN1_CHOOSER_DECLARE(LDAPFilterTemplate)
+
+/* ********************************************************************** */
+
+#define SEC_ASN1_LDAP_STRING SEC_ASN1_OCTET_STRING
+
+#define LDAPATTR_CACERT (1<<0)
+#define LDAPATTR_USERCERT (1<<1)
+#define LDAPATTR_CROSSPAIRCERT (1<<2)
+#define LDAPATTR_CERTREVLIST (1<<3)
+#define LDAPATTR_AUTHREVLIST (1<<4)
+#define MAX_LDAPATTRS 5
+typedef PKIX_UInt32 LdapAttrMask;
+
+typedef enum {
+ SIMPLE_AUTH = 0,
+ KRBV42LDAP_AUTH = 1,
+ KRBV42DSA_AUTH = 2
+} AuthType;
+
+typedef enum {
+ BASE_OBJECT = 0,
+ SINGLE_LEVEL = 1,
+ WHOLE_SUBTREE = 2
+} ScopeType;
+
+typedef enum {
+ NEVER_DEREF = 0,
+ DEREF_IN_SEARCHING = 1,
+ DEREF_FINDING_BASEOBJ = 2,
+ ALWAYS_DEREF = 3
+} DerefType;
+
+typedef enum {
+ LDAP_INITIALSUBSTRING_TYPE = 0,
+ LDAP_ANYSUBSTRING_TYPE = 1,
+ LDAP_FINALSUBSTRING_TYPE = 2
+} LDAPSubstringFilterType;
+
+typedef enum {
+ LDAP_ANDFILTER_TYPE = 0,
+ LDAP_ORFILTER_TYPE = 1,
+ LDAP_NOTFILTER_TYPE = 2,
+ LDAP_EQUALFILTER_TYPE = 3,
+ LDAP_SUBSTRINGFILTER_TYPE = 4,
+ LDAP_GREATEROREQUALFILTER_TYPE = 5,
+ LDAP_LESSOREQUALFILTER_TYPE = 6,
+ LDAP_PRESENTFILTER_TYPE = 7,
+ LDAP_APPROXMATCHFILTER_TYPE = 8
+} LDAPFilterType;
+
+typedef enum {
+ LDAP_BIND_TYPE = 0,
+ LDAP_BINDRESPONSE_TYPE = 1,
+ LDAP_UNBIND_TYPE = 2,
+ LDAP_SEARCH_TYPE = 3,
+ LDAP_SEARCHRESPONSEENTRY_TYPE = 4,
+ LDAP_SEARCHRESPONSERESULT_TYPE = 5,
+ LDAP_ABANDONREQUEST_TYPE = 16
+} LDAPMessageType;
+
+typedef enum {
+ SUCCESS = 0,
+ OPERATIONSERROR = 1,
+ PROTOCOLERROR = 2,
+ TIMELIMITEXCEEDED = 3,
+ SIZELIMITEXCEEDED = 4,
+ COMPAREFALSE = 5,
+ COMPARETRUE = 6,
+ AUTHMETHODNOTSUPPORTED = 7,
+ STRONGAUTHREQUIRED = 8,
+ NOSUCHATTRIBUTE = 16,
+ UNDEFINEDATTRIBUTETYPE = 17,
+ INAPPROPRIATEMATCHING = 18,
+ CONSTRAINTVIOLATION = 19,
+ ATTRIBUTEORVALUEEXISTS = 20,
+ INVALIDATTRIBUTESYNTAX = 21,
+ NOSUCHOBJECT = 32,
+ ALIASPROBLEM = 33,
+ INVALIDDNSYNTAX = 34,
+ ISLEAF = 35,
+ ALIASDEREFERENCINGPROBLEM = 36,
+ INAPPROPRIATEAUTHENTICATION = 48,
+ INVALIDCREDENTIALS = 49,
+ INSUFFICIENTACCESSRIGHTS = 50,
+ BUSY = 51,
+ UNAVAILABLE = 52,
+ UNWILLINGTOPERFORM = 53,
+ LOOPDETECT = 54,
+ NAMINGVIOLATION = 64,
+ OBJECTCLASSVIOLATION = 65,
+ NOTALLOWEDONNONLEAF = 66,
+ NOTALLOWEDONRDN = 67,
+ ENTRYALREADYEXISTS = 68,
+ OBJECTCLASSMODSPROHIBITED = 69,
+ OTHER = 80
+} LDAPResultCode;
+
+typedef struct LDAPLocationStruct LDAPLocation;
+typedef struct LDAPCertPairStruct LDAPCertPair;
+typedef struct LDAPSimpleBindStruct LDAPSimpleBind;
+typedef struct LDAPBindAPIStruct LDAPBindAPI;
+typedef struct LDAPBindStruct LDAPBind;
+typedef struct LDAPResultStruct LDAPBindResponse;
+typedef struct LDAPResultStruct LDAPResult;
+typedef struct LDAPSearchResponseAttrStruct LDAPSearchResponseAttr;
+typedef struct LDAPSearchResponseEntryStruct LDAPSearchResponseEntry;
+typedef struct LDAPResultStruct LDAPSearchResponseResult;
+typedef struct LDAPUnbindStruct LDAPUnbind;
+typedef struct LDAPFilterStruct LDAPFilter;
+typedef struct LDAPAndFilterStruct LDAPAndFilter;
+typedef struct LDAPNotFilterStruct LDAPNotFilter;
+typedef struct LDAPSubstringStruct LDAPSubstring;
+typedef struct LDAPSubstringFilterStruct LDAPSubstringFilter;
+typedef struct LDAPPresentFilterStruct LDAPPresentFilter;
+typedef struct LDAPAttributeValueAssertionStruct LDAPAttributeValueAssertion;
+typedef struct LDAPNameComponentStruct LDAPNameComponent;
+typedef struct LDAPRequestParamsStruct LDAPRequestParams;
+typedef struct LDAPSearchStruct LDAPSearch;
+typedef struct LDAPAbandonRequestStruct LDAPAbandonRequest;
+typedef struct protocolOpStruct LDAPProtocolOp;
+typedef struct LDAPMessageStruct LDAPMessage;
+typedef LDAPAndFilter LDAPOrFilter;
+typedef LDAPAttributeValueAssertion LDAPEqualFilter;
+typedef LDAPAttributeValueAssertion LDAPGreaterOrEqualFilter;
+typedef LDAPAttributeValueAssertion LDAPLessOrEqualFilter;
+typedef LDAPAttributeValueAssertion LDAPApproxMatchFilter;
+
+struct LDAPLocationStruct {
+ PLArenaPool *arena;
+ void *serverSite;
+ void **filterString;
+ void **attrBitString;
+};
+
+struct LDAPCertPairStruct {
+ SECItem forward;
+ SECItem reverse;
+};
+
+struct LDAPSimpleBindStruct {
+ char *bindName;
+ char *authentication;
+};
+
+struct LDAPBindAPIStruct {
+ AuthType selector;
+ union {
+ LDAPSimpleBind simple;
+ } chooser;
+};
+
+struct LDAPBindStruct {
+ SECItem version;
+ SECItem bindName;
+ SECItem authentication;
+};
+
+struct LDAPResultStruct {
+ SECItem resultCode;
+ SECItem matchedDN;
+ SECItem errorMessage;
+};
+
+struct LDAPSearchResponseAttrStruct {
+ SECItem attrType;
+ SECItem **val;
+};
+
+struct LDAPSearchResponseEntryStruct {
+ SECItem objectName;
+ LDAPSearchResponseAttr **attributes;
+};
+
+struct LDAPUnbindStruct {
+ SECItem dummy;
+};
+
+struct LDAPAndFilterStruct {
+ LDAPFilter **filters;
+};
+
+struct LDAPNotFilterStruct {
+ LDAPFilter *filter;
+};
+
+struct LDAPSubstringStruct {
+ LDAPSubstringFilterType selector;
+ SECItem item;
+};
+
+struct LDAPSubstringFilterStruct {
+ SECItem attrType;
+ LDAPSubstring *strings;
+};
+
+struct LDAPPresentFilterStruct {
+ SECItem attrType;
+};
+
+struct LDAPAttributeValueAssertionStruct {
+ SECItem attrType;
+ SECItem attrValue;
+};
+
+struct LDAPFilterStruct {
+ LDAPFilterType selector;
+ union {
+ LDAPAndFilter andFilter;
+ LDAPOrFilter orFilter;
+ LDAPNotFilter notFilter;
+ LDAPEqualFilter equalFilter;
+ LDAPSubstringFilter substringFilter;
+ LDAPGreaterOrEqualFilter greaterOrEqualFilter;
+ LDAPLessOrEqualFilter lessOrEqualFilter;
+ LDAPPresentFilter presentFilter;
+ LDAPApproxMatchFilter approxMatchFilter;
+ } filter;
+};
+
+struct LDAPNameComponentStruct {
+ unsigned char *attrType;
+ unsigned char *attrValue;
+};
+
+struct LDAPRequestParamsStruct {
+ char *baseObject; /* e.g. "c=US" */
+ ScopeType scope;
+ DerefType derefAliases;
+ PKIX_UInt32 sizeLimit; /* 0 = no limit */
+ PRIntervalTime timeLimit; /* 0 = no limit */
+ LDAPNameComponent **nc; /* e.g. {{"cn","xxx"},{"o","yyy"},NULL} */
+ LdapAttrMask attributes;
+};
+
+struct LDAPSearchStruct {
+ SECItem baseObject;
+ SECItem scope;
+ SECItem derefAliases;
+ SECItem sizeLimit;
+ SECItem timeLimit;
+ SECItem attrsOnly;
+ LDAPFilter filter;
+ SECItem **attributes;
+};
+
+struct LDAPAbandonRequestStruct {
+ SECItem messageID;
+};
+
+struct protocolOpStruct {
+ LDAPMessageType selector;
+ union {
+ LDAPBind bindMsg;
+ LDAPBindResponse bindResponseMsg;
+ LDAPUnbind unbindMsg;
+ LDAPSearch searchMsg;
+ LDAPSearchResponseEntry searchResponseEntryMsg;
+ LDAPSearchResponseResult searchResponseResultMsg;
+ LDAPAbandonRequest abandonRequestMsg;
+ } op;
+};
+
+struct LDAPMessageStruct {
+ SECItem messageID;
+ LDAPProtocolOp protocolOp;
+};
+
+typedef struct PKIX_PL_LdapClientStruct PKIX_PL_LdapClient;
+
+typedef PKIX_Error *
+(*PKIX_PL_LdapClient_InitiateFcn)(
+ PKIX_PL_LdapClient *client,
+ LDAPRequestParams *requestParams,
+ void **pNBIO,
+ PKIX_List **pResponse,
+ void *plContext);
+
+typedef PKIX_Error *
+(*PKIX_PL_LdapClient_ResumeFcn)(
+ PKIX_PL_LdapClient *client,
+ void **pNBIO,
+ PKIX_List **pResponse,
+ void *plContext);
+
+struct PKIX_PL_LdapClientStruct {
+ PKIX_PL_LdapClient_InitiateFcn initiateFcn;
+ PKIX_PL_LdapClient_ResumeFcn resumeFcn;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaptemplates.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaptemplates.c
new file mode 100644
index 000000000..ecb681929
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_ldaptemplates.c
@@ -0,0 +1,417 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "pkix_pl_ldapt.h"
+
+SEC_ASN1_MKSUB(SEC_AnyTemplate)
+SEC_ASN1_MKSUB(SEC_NullTemplate)
+SEC_ASN1_MKSUB(SEC_OctetStringTemplate)
+
+/*
+ * CertificatePair ::= SEQUENCE {
+ * forward [0] Certificate OPTIONAL,
+ * reverse [1] Certificate OPTIONAL
+ * -- at least one of the pair shall be present --
+ * }
+ */
+
+const SEC_ASN1Template PKIX_PL_LDAPCrossCertPairTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(LDAPCertPair) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ SEC_ASN1_EXPLICIT | SEC_ASN1_XTRN | 0,
+ offsetof(LDAPCertPair, forward), SEC_ASN1_SUB(SEC_AnyTemplate) },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ SEC_ASN1_EXPLICIT | SEC_ASN1_XTRN | 1,
+ offsetof(LDAPCertPair, reverse), SEC_ASN1_SUB(SEC_AnyTemplate) },
+ { 0 }
+};
+
+/*
+ * BindRequest ::=
+ * [APPLICATION 0] SEQUENCE {
+ * version INTEGER (1..127),
+ * name LDAPDN,
+ * authentication CHOICE {
+ * simple [0] OCTET STRING,
+ * krbv42LDAP [1] OCTET STRING,
+ * krbv42DSA [2] OCTET STRING
+ * }
+ * }
+ *
+ * LDAPDN ::= LDAPString
+ *
+ * LDAPString ::= OCTET STRING
+ */
+
+#define LDAPStringTemplate SEC_ASN1_SUB(SEC_OctetStringTemplate)
+
+static const SEC_ASN1Template LDAPBindApplTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL },
+ { SEC_ASN1_INTEGER, offsetof(LDAPBind, version) },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPBind, bindName) },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPBind, authentication) },
+ { 0 }
+};
+
+static const SEC_ASN1Template LDAPBindTemplate[] = {
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | LDAP_BIND_TYPE, 0,
+ LDAPBindApplTemplate, sizeof (LDAPBind) }
+};
+
+/*
+ * BindResponse ::= [APPLICATION 1] LDAPResult
+ *
+ * LDAPResult ::=
+ * SEQUENCE {
+ * resultCode ENUMERATED {
+ * success (0),
+ * operationsError (1),
+ * protocolError (2),
+ * timeLimitExceeded (3),
+ * sizeLimitExceeded (4),
+ * compareFalse (5),
+ * compareTrue (6),
+ * authMethodNotSupported (7),
+ * strongAuthRequired (8),
+ * noSuchAttribute (16),
+ * undefinedAttributeType (17),
+ * inappropriateMatching (18),
+ * constraintViolation (19),
+ * attributeOrValueExists (20),
+ * invalidAttributeSyntax (21),
+ * noSuchObject (32),
+ * aliasProblem (33),
+ * invalidDNSyntax (34),
+ * isLeaf (35),
+ * aliasDereferencingProblem (36),
+ * inappropriateAuthentication (48),
+ * invalidCredentials (49),
+ * insufficientAccessRights (50),
+ * busy (51),
+ * unavailable (52),
+ * unwillingToPerform (53),
+ * loopDetect (54),
+ * namingViolation (64),
+ * objectClassViolation (65),
+ * notAllowedOnNonLeaf (66),
+ * notAllowedOnRDN (67),
+ * entryAlreadyExists (68),
+ * objectClassModsProhibited (69),
+ * other (80)
+ * },
+ * matchedDN LDAPDN,
+ * errorMessage LDAPString
+ * }
+ */
+
+static const SEC_ASN1Template LDAPResultTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL },
+ { SEC_ASN1_ENUMERATED, offsetof(LDAPResult, resultCode) },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPResult, matchedDN) },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPResult, errorMessage) },
+ { 0 }
+};
+
+static const SEC_ASN1Template LDAPBindResponseTemplate[] = {
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | LDAP_BINDRESPONSE_TYPE, 0,
+ LDAPResultTemplate, sizeof (LDAPBindResponse) }
+};
+
+/*
+ * UnbindRequest ::= [APPLICATION 2] NULL
+ */
+
+static const SEC_ASN1Template LDAPUnbindTemplate[] = {
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | SEC_ASN1_XTRN |
+ LDAP_UNBIND_TYPE , 0, SEC_ASN1_SUB(SEC_NullTemplate) }
+};
+
+/*
+ * AttributeValueAssertion ::=
+ * SEQUENCE {
+ * attributeType AttributeType,
+ * attributeValue AttributeValue,
+ * }
+ *
+ * AttributeType ::= LDAPString
+ * -- text name of the attribute, or dotted
+ * -- OID representation
+ *
+ * AttributeValue ::= OCTET STRING
+ */
+
+#define LDAPAttributeTypeTemplate LDAPStringTemplate
+
+/*
+ * SubstringFilter ::=
+ * SEQUENCE {
+ * type AttributeType,
+ * SEQUENCE OF CHOICE {
+ * initial [0] LDAPString,
+ * any [1] LDAPString,
+ * final [2] LDAPString,
+ * }
+ * }
+ */
+
+#define LDAPSubstringFilterInitialTemplate LDAPStringTemplate
+#define LDAPSubstringFilterAnyTemplate LDAPStringTemplate
+#define LDAPSubstringFilterFinalTemplate LDAPStringTemplate
+
+static const SEC_ASN1Template LDAPSubstringFilterChoiceTemplate[] = {
+ { SEC_ASN1_CHOICE, offsetof(LDAPSubstring, selector), 0,
+ sizeof (LDAPFilter) },
+ { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 0,
+ offsetof(LDAPSubstring, item),
+ LDAPSubstringFilterInitialTemplate,
+ LDAP_INITIALSUBSTRING_TYPE },
+ { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 1,
+ offsetof(LDAPSubstring, item),
+ LDAPSubstringFilterAnyTemplate,
+ LDAP_ANYSUBSTRING_TYPE },
+ { SEC_ASN1_CONTEXT_SPECIFIC | SEC_ASN1_XTRN | 2,
+ offsetof(LDAPSubstring, item),
+ LDAPSubstringFilterFinalTemplate,
+ LDAP_FINALSUBSTRING_TYPE },
+ { 0 }
+};
+
+/*
+ * Filter ::=
+ * CHOICE {
+ * and [0] SET OF Filter,
+ * or [1] SET OF Filter,
+ * not [2] Filter,
+ * equalityMatch [3] AttributeValueAssertion,
+ * substrings [4] SubstringFilter,
+ * greaterOrEqual [5] AttributeValueAssertion,
+ * lessOrEqual [6] AttributeValueAssertion,
+ * present [7] AttributeType,
+ * approxMatch [8] AttributeValueAssertion
+ }
+ */
+
+static const SEC_ASN1Template LDAPSubstringFilterTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (LDAPSubstringFilter) },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPSubstringFilter, attrType) },
+ { SEC_ASN1_SEQUENCE_OF, offsetof(LDAPSubstringFilter, strings),
+ LDAPSubstringFilterChoiceTemplate },
+ { 0 }
+};
+
+const SEC_ASN1Template LDAPFilterTemplate[]; /* forward reference */
+
+static const SEC_ASN1Template LDAPSetOfFiltersTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, LDAPFilterTemplate }
+};
+
+static const SEC_ASN1Template LDAPAVAFilterTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof (LDAPAttributeValueAssertion) },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPAttributeValueAssertion, attrType) },
+ { SEC_ASN1_OCTET_STRING, offsetof(LDAPAttributeValueAssertion, attrValue) },
+ { 0 }
+};
+
+static const SEC_ASN1Template LDAPPresentFilterTemplate[] = {
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPPresentFilter, attrType) }
+};
+
+#define LDAPEqualFilterTemplate LDAPAVAFilterTemplate
+#define LDAPGreaterOrEqualFilterTemplate LDAPAVAFilterTemplate
+#define LDAPLessOrEqualFilterTemplate LDAPAVAFilterTemplate
+#define LDAPApproxMatchFilterTemplate LDAPAVAFilterTemplate
+
+const SEC_ASN1Template LDAPFilterTemplate[] = {
+ { SEC_ASN1_CHOICE, offsetof(LDAPFilter, selector), 0, sizeof(LDAPFilter) },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_ANDFILTER_TYPE,
+ offsetof(LDAPFilter, filter.andFilter.filters),
+ LDAPSetOfFiltersTemplate, LDAP_ANDFILTER_TYPE },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_ORFILTER_TYPE,
+ offsetof(LDAPFilter, filter.orFilter.filters),
+ LDAPSetOfFiltersTemplate, LDAP_ORFILTER_TYPE },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_NOTFILTER_TYPE | SEC_ASN1_POINTER,
+ offsetof(LDAPFilter, filter.notFilter),
+ LDAPFilterTemplate, LDAP_NOTFILTER_TYPE },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_EQUALFILTER_TYPE,
+ offsetof(LDAPFilter, filter.equalFilter),
+ LDAPEqualFilterTemplate, LDAP_EQUALFILTER_TYPE },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_SUBSTRINGFILTER_TYPE, offsetof(LDAPFilter, filter.substringFilter),
+ LDAPSubstringFilterTemplate, LDAP_SUBSTRINGFILTER_TYPE },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_GREATEROREQUALFILTER_TYPE,
+ offsetof(LDAPFilter, filter.greaterOrEqualFilter),
+ LDAPGreaterOrEqualFilterTemplate, LDAP_GREATEROREQUALFILTER_TYPE },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_LESSOREQUALFILTER_TYPE,
+ offsetof(LDAPFilter, filter.lessOrEqualFilter),
+ LDAPLessOrEqualFilterTemplate, LDAP_LESSOREQUALFILTER_TYPE },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_PRESENTFILTER_TYPE,
+ offsetof(LDAPFilter, filter.presentFilter),
+ LDAPPresentFilterTemplate, LDAP_PRESENTFILTER_TYPE },
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_CONTEXT_SPECIFIC |
+ LDAP_APPROXMATCHFILTER_TYPE,
+ offsetof(LDAPFilter, filter.approxMatchFilter),
+ LDAPApproxMatchFilterTemplate, LDAP_APPROXMATCHFILTER_TYPE },
+ { 0 }
+};
+
+/*
+ * SearchRequest ::=
+ * [APPLICATION 3] SEQUENCE {
+ * baseObject LDAPDN,
+ * scope ENUMERATED {
+ * baseObject (0),
+ * singleLevel (1),
+ * wholeSubtree (2)
+ * },
+ * derefAliases ENUMERATED {
+ * neverDerefAliases (0),
+ * derefInSearching (1),
+ * derefFindingBaseObj (2),
+ * alwaysDerefAliases (3)
+ * },
+ * sizeLimit INTEGER (0 .. MAXINT),
+ * -- value of 0 implies no sizeLimit
+ * timeLimit INTEGER (0 .. MAXINT),
+ * -- value of 0 implies no timeLimit
+ * attrsOnly BOOLEAN,
+ * -- TRUE, if only attributes (without values)
+ * -- to be returned
+ * filter Filter,
+ * attributes SEQUENCE OF AttributeType
+ * }
+ */
+
+static const SEC_ASN1Template LDAPAttributeTemplate[] = {
+ { SEC_ASN1_LDAP_STRING, 0, NULL, sizeof (SECItem) }
+};
+
+static const SEC_ASN1Template LDAPSearchApplTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPSearch, baseObject) },
+ { SEC_ASN1_ENUMERATED, offsetof(LDAPSearch, scope) },
+ { SEC_ASN1_ENUMERATED, offsetof(LDAPSearch, derefAliases) },
+ { SEC_ASN1_INTEGER, offsetof(LDAPSearch, sizeLimit) },
+ { SEC_ASN1_INTEGER, offsetof(LDAPSearch, timeLimit) },
+ { SEC_ASN1_BOOLEAN, offsetof(LDAPSearch, attrsOnly) },
+ { SEC_ASN1_INLINE, offsetof(LDAPSearch, filter), LDAPFilterTemplate },
+ { SEC_ASN1_SEQUENCE_OF, offsetof(LDAPSearch, attributes), LDAPAttributeTemplate },
+ { 0 }
+};
+
+static const SEC_ASN1Template LDAPSearchTemplate[] = {
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | LDAP_SEARCH_TYPE, 0,
+ LDAPSearchApplTemplate, sizeof (LDAPSearch) }
+};
+
+/*
+ * SearchResponse ::=
+ * CHOICE {
+ * entry [APPLICATION 4] SEQUENCE {
+ * objectName LDAPDN,
+ * attributes SEQUENCE OF SEQUENCE {
+ * AttributeType,
+ * SET OF AttributeValue
+ * }
+ * }
+ * resultCode [APPLICATION 5] LDAPResult
+ * }
+ */
+
+static const SEC_ASN1Template LDAPSearchResponseAttrTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(LDAPSearchResponseAttr) },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPSearchResponseAttr, attrType) },
+ { SEC_ASN1_SET_OF | SEC_ASN1_XTRN, offsetof(LDAPSearchResponseAttr, val),
+ LDAPStringTemplate },
+ { 0 }
+};
+
+static const SEC_ASN1Template LDAPEntryTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL },
+ { SEC_ASN1_LDAP_STRING, offsetof(LDAPSearchResponseEntry, objectName) },
+ { SEC_ASN1_SEQUENCE_OF, offsetof(LDAPSearchResponseEntry, attributes),
+ LDAPSearchResponseAttrTemplate },
+ { 0 }
+};
+
+static const SEC_ASN1Template LDAPSearchResponseEntryTemplate[] = {
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | LDAP_SEARCHRESPONSEENTRY_TYPE, 0,
+ LDAPEntryTemplate, sizeof (LDAPSearchResponseEntry) }
+};
+
+static const SEC_ASN1Template LDAPSearchResponseResultTemplate[] = {
+ { SEC_ASN1_APPLICATION | LDAP_SEARCHRESPONSERESULT_TYPE, 0,
+ LDAPResultTemplate, sizeof (LDAPSearchResponseResult) }
+};
+
+/*
+ * AbandonRequest ::=
+ * [APPLICATION 16] MessageID
+ */
+
+static const SEC_ASN1Template LDAPAbandonTemplate[] = {
+ { SEC_ASN1_INTEGER, offsetof(LDAPAbandonRequest, messageID) }
+};
+
+static const SEC_ASN1Template LDAPAbandonRequestTemplate[] = {
+ { SEC_ASN1_CONSTRUCTED | SEC_ASN1_APPLICATION | LDAP_ABANDONREQUEST_TYPE, 0,
+ LDAPAbandonTemplate, sizeof (LDAPAbandonRequest) }
+};
+
+/*
+ * LDAPMessage ::=
+ * SEQUENCE {
+ * messageID MessageID,
+ * protocolOp CHOICE {
+ * bindRequest BindRequest,
+ * bindResponse BindResponse,
+ * unbindRequest UnbindRequest,
+ * searchRequest SearchRequest,
+ * searchResponse SearchResponse,
+ * abandonRequest AbandonRequest
+ * }
+ * }
+ *
+ * (other choices exist, not shown)
+ *
+ * MessageID ::= INTEGER (0 .. maxInt)
+ */
+
+static const SEC_ASN1Template LDAPMessageProtocolOpTemplate[] = {
+ { SEC_ASN1_CHOICE, offsetof(LDAPProtocolOp, selector), 0, sizeof (LDAPProtocolOp) },
+ { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.bindMsg),
+ LDAPBindTemplate, LDAP_BIND_TYPE },
+ { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.bindResponseMsg),
+ LDAPBindResponseTemplate, LDAP_BINDRESPONSE_TYPE },
+ { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.unbindMsg),
+ LDAPUnbindTemplate, LDAP_UNBIND_TYPE },
+ { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.searchMsg),
+ LDAPSearchTemplate, LDAP_SEARCH_TYPE },
+ { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.searchResponseEntryMsg),
+ LDAPSearchResponseEntryTemplate, LDAP_SEARCHRESPONSEENTRY_TYPE },
+ { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.searchResponseResultMsg),
+ LDAPSearchResponseResultTemplate, LDAP_SEARCHRESPONSERESULT_TYPE },
+ { SEC_ASN1_INLINE, offsetof(LDAPProtocolOp, op.abandonRequestMsg),
+ LDAPAbandonRequestTemplate, LDAP_ABANDONREQUEST_TYPE },
+ { 0 }
+};
+
+const SEC_ASN1Template PKIX_PL_LDAPMessageTemplate[] = {
+ { SEC_ASN1_SEQUENCE, 0, NULL },
+ { SEC_ASN1_INTEGER, offsetof(LDAPMessage, messageID) },
+ { SEC_ASN1_INLINE, offsetof(LDAPMessage, protocolOp),
+ LDAPMessageProtocolOpTemplate },
+ { 0 }
+};
+
+/* This function simply returns the address of the message template.
+ * This is necessary for Windows DLLs.
+ */
+SEC_ASN1_CHOOSER_IMPLEMENT(PKIX_PL_LDAPMessageTemplate)
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.c
new file mode 100755
index 000000000..171427558
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.c
@@ -0,0 +1,319 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_nsscontext.c
+ *
+ * NSSContext Function Definitions
+ *
+ */
+
+
+#include "pkix_pl_nsscontext.h"
+
+#define PKIX_DEFAULT_MAX_RESPONSE_LENGTH 64 * 1024
+#define PKIX_DEFAULT_COMM_TIMEOUT_SECONDS 60
+
+#define PKIX_DEFAULT_CRL_RELOAD_DELAY_SECONDS 6 * 24 * 60 * 60
+#define PKIX_DEFAULT_BAD_CRL_RELOAD_DELAY_SECONDS 60 * 60
+
+/* --Public-NSSContext-Functions--------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_NssContext_Create
+ * (see comments in pkix_samples_modules.h)
+ */
+PKIX_Error *
+PKIX_PL_NssContext_Create(
+ PKIX_UInt32 certificateUsage,
+ PKIX_Boolean useNssArena,
+ void *wincx,
+ void **pNssContext)
+{
+ PKIX_PL_NssContext *context = NULL;
+ PLArenaPool *arena = NULL;
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_Create");
+ PKIX_NULLCHECK_ONE(pNssContext);
+
+ PKIX_CHECK(PKIX_PL_Malloc
+ (sizeof(PKIX_PL_NssContext), (void **)&context, NULL),
+ PKIX_MALLOCFAILED);
+
+ if (useNssArena == PKIX_TRUE) {
+ PKIX_CONTEXT_DEBUG("\t\tCalling PORT_NewArena\n");
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ }
+
+ context->arena = arena;
+ context->certificateUsage = (SECCertificateUsage)certificateUsage;
+ context->wincx = wincx;
+ context->timeoutSeconds = PKIX_DEFAULT_COMM_TIMEOUT_SECONDS;
+ context->maxResponseLength = PKIX_DEFAULT_MAX_RESPONSE_LENGTH;
+ context->crlReloadDelay = PKIX_DEFAULT_CRL_RELOAD_DELAY_SECONDS;
+ context->badDerCrlReloadDelay =
+ PKIX_DEFAULT_BAD_CRL_RELOAD_DELAY_SECONDS;
+ context->chainVerifyCallback.isChainValid = NULL;
+ context->chainVerifyCallback.isChainValidArg = NULL;
+ *pNssContext = context;
+
+cleanup:
+
+ PKIX_RETURN(CONTEXT);
+}
+
+
+/*
+ * FUNCTION: PKIX_PL_NssContext_Destroy
+ * (see comments in pkix_samples_modules.h)
+ */
+PKIX_Error *
+PKIX_PL_NssContext_Destroy(
+ void *nssContext)
+{
+ void *plContext = NULL;
+ PKIX_PL_NssContext *context = NULL;
+
+ PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_Destroy");
+ PKIX_NULLCHECK_ONE(nssContext);
+
+ context = (PKIX_PL_NssContext*)nssContext;
+
+ if (context->arena != NULL) {
+ PKIX_CONTEXT_DEBUG("\t\tCalling PORT_FreeArena\n");
+ PORT_FreeArena(context->arena, PKIX_FALSE);
+ }
+
+ PKIX_PL_Free(nssContext, NULL);
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_NssContext_GetCertUsage
+ * DESCRIPTION:
+ *
+ * This function obtains the platform-dependent SECCertificateUsage parameter
+ * from the context object pointed to by "nssContext", storing the result at
+ * "pCertUsage".
+ *
+ * PARAMETERS:
+ * "nssContext"
+ * The address of the context object whose wincx parameter is to be
+ * obtained. Must be non-NULL.
+ * "pCertUsage"
+ * The address where the result is stored. Must be non-NULL.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_NssContext_GetCertUsage(
+ PKIX_PL_NssContext *nssContext,
+ SECCertificateUsage *pCertUsage)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_GetCertUsage");
+ PKIX_NULLCHECK_TWO(nssContext, pCertUsage);
+
+ *pCertUsage = nssContext->certificateUsage;
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_NssContext_SetCertUsage
+ * DESCRIPTION:
+ *
+ * This function sets the platform-dependent SECCertificateUsage parameter in
+ * the context object pointed to by "nssContext" to the value provided in
+ * "certUsage".
+ *
+ * PARAMETERS:
+ * "certUsage"
+ * Platform-dependent value to be stored.
+ * "nssContext"
+ * The address of the context object whose wincx parameter is to be
+ * obtained. Must be non-NULL.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_NssContext_SetCertUsage(
+ SECCertificateUsage certUsage,
+ PKIX_PL_NssContext *nssContext)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_SetCertUsage");
+ PKIX_NULLCHECK_ONE(nssContext);
+
+ nssContext->certificateUsage = certUsage;
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_NssContext_GetWincx
+ * DESCRIPTION:
+ *
+ * This function obtains the platform-dependent wincx parameter from the
+ * context object pointed to by "nssContext", storing the result at "pWincx".
+ *
+ * PARAMETERS:
+ * "nssContext"
+ * The address of the context object whose wincx parameter is to be
+ * obtained. Must be non-NULL.
+ * "pWincx"
+ * The address where the result is stored. Must be non-NULL.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_NssContext_GetWincx(
+ PKIX_PL_NssContext *nssContext,
+ void **pWincx)
+{
+ void *plContext = NULL;
+ PKIX_PL_NssContext *context = NULL;
+
+ PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_GetWincx");
+ PKIX_NULLCHECK_TWO(nssContext, pWincx);
+
+ context = (PKIX_PL_NssContext *)nssContext;
+
+ *pWincx = context->wincx;
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: pkix_pl_NssContext_SetWincx
+ * DESCRIPTION:
+ *
+ * This function sets the platform-dependent wincx parameter in the context
+ * object pointed to by "nssContext" to the value provided in "wincx".
+ *
+ * PARAMETERS:
+ * "wincx"
+ * Platform-dependent value to be stored.
+ * "nssContext"
+ * The address of the context object whose wincx parameter is to be
+ * obtained. Must be non-NULL.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_NssContext_SetWincx(
+ void *wincx,
+ PKIX_PL_NssContext *nssContext)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "pkix_pl_NssContext_SetWincx");
+ PKIX_NULLCHECK_ONE(nssContext);
+
+ nssContext->wincx = wincx;
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_NssContext_SetTimeout
+ * DESCRIPTION:
+ *
+ * Sets user defined socket timeout for the validation
+ * session. Default is 60 seconds.
+ *
+ */
+PKIX_Error *
+PKIX_PL_NssContext_SetTimeout(PKIX_UInt32 timeout,
+ PKIX_PL_NssContext *nssContext)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_SetTimeout");
+ PKIX_NULLCHECK_ONE(nssContext);
+
+ nssContext->timeoutSeconds = timeout;
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_NssContext_SetMaxResponseLen
+ * DESCRIPTION:
+ *
+ * Sets user defined maximum transmission length of a message.
+ *
+ */
+PKIX_Error *
+PKIX_PL_NssContext_SetMaxResponseLen(PKIX_UInt32 len,
+ PKIX_PL_NssContext *nssContext)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_SetMaxResponseLen");
+ PKIX_NULLCHECK_ONE(nssContext);
+
+ nssContext->maxResponseLength = len;
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_NssContext_SetCrlReloadDelay
+ * DESCRIPTION:
+ *
+ * Sets user defined delay between attempts to load crl using
+ * CRLDP.
+ *
+ */
+PKIX_Error *
+PKIX_PL_NssContext_SetCrlReloadDelay(PKIX_UInt32 delay,
+ PKIX_PL_NssContext *nssContext)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_SetCrlReloadDelay");
+ PKIX_NULLCHECK_ONE(nssContext);
+
+ nssContext->crlReloadDelay = delay;
+
+ PKIX_RETURN(CONTEXT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_NssContext_SetBadDerCrlReloadDelay
+ * DESCRIPTION:
+ *
+ * Sets user defined delay between attempts to load crl that
+ * failed to decode.
+ *
+ */
+PKIX_Error *
+PKIX_PL_NssContext_SetBadDerCrlReloadDelay(PKIX_UInt32 delay,
+ PKIX_PL_NssContext *nssContext)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(CONTEXT, "PKIX_PL_NssContext_SetBadDerCrlReloadDelay");
+ PKIX_NULLCHECK_ONE(nssContext);
+
+ nssContext->badDerCrlReloadDelay = delay;
+
+ PKIX_RETURN(CONTEXT);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.h
new file mode 100755
index 000000000..04441c2b2
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_nsscontext.h
@@ -0,0 +1,52 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_nsscontext.h
+ *
+ * NSSContext Object Type Definition
+ *
+ */
+
+
+#ifndef _PKIX_PL_NSSCONTEXT_H
+#define _PKIX_PL_NSSCONTEXT_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_NssContextStruct {
+ SECCertificateUsage certificateUsage;
+ PLArenaPool *arena;
+ void *wincx;
+ PKIX_UInt32 timeoutSeconds;
+ PKIX_UInt32 maxResponseLength;
+ PRTime crlReloadDelay;
+ PRTime badDerCrlReloadDelay;
+ CERTChainVerifyCallback chainVerifyCallback;
+};
+
+PKIX_Error *
+pkix_pl_NssContext_GetCertUsage
+ (PKIX_PL_NssContext *nssContext, SECCertificateUsage *pCertUsage);
+
+/* XXX move the setter into the public header. */
+PKIX_Error *
+pkix_pl_NssContext_SetCertUsage
+ (SECCertificateUsage certUsage, PKIX_PL_NssContext *nssContext);
+
+PKIX_Error *
+pkix_pl_NssContext_GetWincx(PKIX_PL_NssContext *nssContext, void **pWincx);
+
+/* XXX move the setter into the public header. */
+PKIX_Error *
+pkix_pl_NssContext_SetWincx(void *wincx, PKIX_PL_NssContext *nssContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_NSSCONTEXT_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c
new file mode 100755
index 000000000..7de614ea6
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.c
@@ -0,0 +1,1039 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_pk11certstore.c
+ *
+ * PKCS11CertStore Function Definitions
+ *
+ */
+
+#include "pkix_pl_pk11certstore.h"
+
+/*
+ * PKIX_DEFAULT_MAX_RESPONSE_LENGTH (64 * 1024) is too small for downloading
+ * CRLs. We observed CRLs of sizes 338759 and 439035 in practice. So we
+ * need to use a higher max response length for CRLs.
+ */
+#define PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH (512 * 1024)
+
+/* --Private-Pk11CertStore-Functions---------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_CheckTrust
+ * DESCRIPTION:
+ * This function checks the trust status of this "cert" that was retrieved
+ * from the CertStore "store" and returns its trust status at "pTrusted".
+ *
+ * PARAMETERS:
+ * "store"
+ * Address of the CertStore. Must be non-NULL.
+ * "cert"
+ * Address of the Cert. Must be non-NULL.
+ * "pTrusted"
+ * Address of PKIX_Boolean where the "cert" trust status is returned.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Pk11CertStore_CheckTrust(
+ PKIX_CertStore *store,
+ PKIX_PL_Cert *cert,
+ PKIX_Boolean *pTrusted,
+ void *plContext)
+{
+ SECStatus rv = SECFailure;
+ PKIX_Boolean trusted = PKIX_FALSE;
+ SECCertUsage certUsage = 0;
+ SECCertificateUsage certificateUsage;
+ unsigned int requiredFlags;
+ SECTrustType trustType;
+ CERTCertTrust trust;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CheckTrust");
+ PKIX_NULLCHECK_THREE(store, cert, pTrusted);
+ PKIX_NULLCHECK_ONE(cert->nssCert);
+
+ certificateUsage = ((PKIX_PL_NssContext*)plContext)->certificateUsage;
+
+ /* ensure we obtained a single usage bit only */
+ PORT_Assert(!(certificateUsage & (certificateUsage - 1)));
+
+ /* convert SECertificateUsage (bit mask) to SECCertUsage (enum) */
+ while (0 != (certificateUsage = certificateUsage >> 1)) { certUsage++; }
+
+ rv = CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags, &trustType);
+ if (rv == SECSuccess) {
+ rv = CERT_GetCertTrust(cert->nssCert, &trust);
+ }
+
+ if (rv == SECSuccess) {
+ unsigned int certFlags;
+
+ if (certUsage != certUsageAnyCA &&
+ certUsage != certUsageStatusResponder) {
+ CERTCertificate *nssCert = cert->nssCert;
+
+ if (certUsage == certUsageVerifyCA) {
+ if (nssCert->nsCertType & NS_CERT_TYPE_EMAIL_CA) {
+ trustType = trustEmail;
+ } else if (nssCert->nsCertType & NS_CERT_TYPE_SSL_CA) {
+ trustType = trustSSL;
+ } else {
+ trustType = trustObjectSigning;
+ }
+ }
+
+ certFlags = SEC_GET_TRUST_FLAGS((&trust), trustType);
+ if ((certFlags & requiredFlags) == requiredFlags) {
+ trusted = PKIX_TRUE;
+ }
+ } else {
+ for (trustType = trustSSL; trustType < trustTypeNone;
+ trustType++) {
+ certFlags =
+ SEC_GET_TRUST_FLAGS((&trust), trustType);
+ if ((certFlags & requiredFlags) == requiredFlags) {
+ trusted = PKIX_TRUE;
+ break;
+ }
+ }
+ }
+ }
+
+ *pTrusted = trusted;
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_CertQuery
+ * DESCRIPTION:
+ *
+ * This function obtains from the database the Certs specified by the
+ * ComCertSelParams pointed to by "params" and stores the resulting
+ * List at "pSelected". If no matching Certs are found, a NULL pointer
+ * will be stored.
+ *
+ * This function uses a "smart" database query if the Subject has been set
+ * in ComCertSelParams. Otherwise, it uses a very inefficient call to
+ * retrieve all Certs in the database (and run them through the selector).
+ *
+ * PARAMETERS:
+ * "params"
+ * Address of the ComCertSelParams. Must be non-NULL.
+ * "pSelected"
+ * Address at which List will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Pk11CertStore_CertQuery(
+ PKIX_ComCertSelParams *params,
+ PKIX_List **pSelected,
+ void *plContext)
+{
+ PRBool validOnly = PR_FALSE;
+ PRTime prtime = 0;
+ PKIX_PL_X500Name *subjectName = NULL;
+ PKIX_PL_Date *certValid = NULL;
+ PKIX_List *certList = NULL;
+ PKIX_PL_Cert *cert = NULL;
+ CERTCertList *pk11CertList = NULL;
+ CERTCertListNode *node = NULL;
+ CERTCertificate *nssCert = NULL;
+ CERTCertDBHandle *dbHandle = NULL;
+
+ PLArenaPool *arena = NULL;
+ SECItem *nameItem = NULL;
+ void *wincx = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CertQuery");
+ PKIX_NULLCHECK_TWO(params, pSelected);
+
+ /* avoid multiple calls to retrieve a constant */
+ PKIX_PL_NSSCALLRV(CERTSTORE, dbHandle, CERT_GetDefaultCertDB, ());
+
+ /*
+ * Any of the ComCertSelParams may be obtained and used to constrain
+ * the database query, to allow the use of a "smart" query. See
+ * pkix_certsel.h for a list of the PKIX_ComCertSelParams_Get*
+ * calls available. No corresponding "smart" queries exist at present,
+ * except for CERT_CreateSubjectCertList based on Subject. When others
+ * are added, corresponding code should be added to
+ * pkix_pl_Pk11CertStore_CertQuery to use them when appropriate
+ * selector parameters have been set.
+ */
+
+ PKIX_CHECK(PKIX_ComCertSelParams_GetSubject
+ (params, &subjectName, plContext),
+ PKIX_COMCERTSELPARAMSGETSUBJECTFAILED);
+
+ PKIX_CHECK(PKIX_ComCertSelParams_GetCertificateValid
+ (params, &certValid, plContext),
+ PKIX_COMCERTSELPARAMSGETCERTIFICATEVALIDFAILED);
+
+ /* If caller specified a Date, convert it to PRTime */
+ if (certValid) {
+ PKIX_CHECK(pkix_pl_Date_GetPRTime
+ (certValid, &prtime, plContext),
+ PKIX_DATEGETPRTIMEFAILED);
+ validOnly = PR_TRUE;
+ }
+
+ /*
+ * If we have the subject name for the desired subject,
+ * ask the database for Certs with that subject. Otherwise
+ * ask the database for all Certs.
+ */
+ if (subjectName) {
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena) {
+
+ PKIX_CHECK(pkix_pl_X500Name_GetDERName
+ (subjectName, arena, &nameItem, plContext),
+ PKIX_X500NAMEGETSECNAMEFAILED);
+
+ if (nameItem) {
+
+ PKIX_PL_NSSCALLRV
+ (CERTSTORE,
+ pk11CertList,
+ CERT_CreateSubjectCertList,
+ (NULL, dbHandle, nameItem, prtime, validOnly));
+ }
+ PKIX_PL_NSSCALL
+ (CERTSTORE, PORT_FreeArena, (arena, PR_FALSE));
+ arena = NULL;
+ }
+
+ } else {
+
+ PKIX_CHECK(pkix_pl_NssContext_GetWincx
+ ((PKIX_PL_NssContext *)plContext, &wincx),
+ PKIX_NSSCONTEXTGETWINCXFAILED);
+
+ PKIX_PL_NSSCALLRV
+ (CERTSTORE,
+ pk11CertList,
+ PK11_ListCerts,
+ (PK11CertListAll, wincx));
+ }
+
+ if (pk11CertList) {
+
+ PKIX_CHECK(PKIX_List_Create(&certList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ for (node = CERT_LIST_HEAD(pk11CertList);
+ !(CERT_LIST_END(node, pk11CertList));
+ node = CERT_LIST_NEXT(node)) {
+
+ PKIX_PL_NSSCALLRV
+ (CERTSTORE,
+ nssCert,
+ CERT_DupCertificate,
+ (node->cert));
+
+ if (!nssCert) {
+ continue; /* just skip bad certs */
+ }
+
+ PKIX_CHECK_ONLY_FATAL(pkix_pl_Cert_CreateWithNSSCert
+ (nssCert, &cert, plContext),
+ PKIX_CERTCREATEWITHNSSCERTFAILED);
+
+ if (PKIX_ERROR_RECEIVED) {
+ CERT_DestroyCertificate(nssCert);
+ nssCert = NULL;
+ continue; /* just skip bad certs */
+ }
+
+ PKIX_CHECK_ONLY_FATAL(PKIX_List_AppendItem
+ (certList, (PKIX_PL_Object *)cert, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(cert);
+
+ }
+
+ /* Don't throw away the list if one cert was bad! */
+ pkixTempErrorReceived = PKIX_FALSE;
+ }
+
+ *pSelected = certList;
+ certList = NULL;
+
+cleanup:
+
+ if (pk11CertList) {
+ CERT_DestroyCertList(pk11CertList);
+ }
+ if (arena) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ PKIX_DECREF(subjectName);
+ PKIX_DECREF(certValid);
+ PKIX_DECREF(cert);
+ PKIX_DECREF(certList);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_ImportCrl
+ * DESCRIPTION:
+ *
+ * PARAMETERS:
+ * "params"
+ * Address of the ComCRLSelParams. Must be non-NULL.
+ * "pSelected"
+ * Address at which List will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Pk11CertStore_ImportCrl(
+ PKIX_CertStore *store,
+ PKIX_PL_X500Name *issuerName,
+ PKIX_List *crlList,
+ void *plContext)
+{
+ CERTCertDBHandle *certHandle = CERT_GetDefaultCertDB();
+ PKIX_PL_CRL *crl = NULL;
+ SECItem *derCrl = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_ImportCrl");
+ PKIX_NULLCHECK_TWO(store, plContext);
+
+ if (!crlList) {
+ goto cleanup;
+ }
+ while (crlList->length > 0) {
+ PKIX_CHECK(
+ PKIX_List_GetItem(crlList, 0, (PKIX_PL_Object**)&crl,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ /* Delete crl from the list to keep controll of the
+ * last reference. crl need to be destroyed right after
+ * it released the ownership of the crl der. */
+ PKIX_CHECK(
+ PKIX_List_DeleteItem(crlList, 0, plContext),
+ PKIX_LISTDELETEITEMFAILED);
+
+ /* acquire the crlder ownership */
+ pkixErrorResult =
+ PKIX_PL_CRL_ReleaseDerCrl(crl, &derCrl, plContext);
+ PORT_Assert(!pkixErrorResult && derCrl);
+ if (pkixErrorResult || !derCrl) {
+ /* All pkix delivered crls should be able to
+ * release their ders. */
+ PKIX_DECREF(pkixErrorResult);
+ PKIX_DECREF(crl);
+ continue;
+ }
+ cert_CacheCRLByGeneralName(certHandle, derCrl,
+ crl->derGenName);
+ /* Do not check the status. If it is a SECFailure,
+ * derCrl is already destroyed. */
+ derCrl = NULL;
+ PKIX_DECREF(crl);
+ }
+
+cleanup:
+ PKIX_DECREF(crl);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+static PKIX_Error *
+NameCacheHasFetchedCrlInfo(PKIX_PL_Cert *pkixCert,
+ PRTime time,
+ PKIX_Boolean *pHasFetchedCrlInCache,
+ void *plContext)
+{
+ /* Returning true result in this case will mean, that case info
+ * is currect and should used as is. */
+ NamedCRLCache* nameCrlCache = NULL;
+ PKIX_Boolean hasFetchedCrlInCache = PKIX_TRUE;
+ PKIX_List *dpList = NULL;
+ pkix_pl_CrlDp *dp = NULL;
+ PKIX_UInt32 dpIndex = 0;
+ SECStatus rv = SECSuccess;
+ PRTime reloadDelay = 0, badCrlInvalDelay = 0;
+
+ PKIX_ENTER(CERTSTORE, "ChechCacheHasFetchedCrl");
+
+ reloadDelay =
+ ((PKIX_PL_NssContext*)plContext)->crlReloadDelay *
+ PR_USEC_PER_SEC;
+ badCrlInvalDelay =
+ ((PKIX_PL_NssContext*)plContext)->badDerCrlReloadDelay *
+ PR_USEC_PER_SEC;
+ if (!time) {
+ time = PR_Now();
+ }
+ /* If we already download the crl and inserted into the cache, then
+ * there is no need to check for fetched crl. We have what we have. */
+ PKIX_CHECK(
+ PKIX_PL_Cert_GetCrlDp(pkixCert, &dpList, plContext),
+ PKIX_CERTGETCRLDPFAILED);
+ if (dpList && dpList->length) {
+ hasFetchedCrlInCache = PKIX_FALSE;
+ rv = cert_AcquireNamedCRLCache(&nameCrlCache);
+ if (rv != SECSuccess) {
+ PKIX_DECREF(dpList);
+ }
+ } else {
+ /* If no dp then treat it as if we already have
+ * a fetched crl. */
+ PKIX_DECREF(dpList);
+ }
+ for (;!hasFetchedCrlInCache &&
+ dpList && dpIndex < dpList->length;dpIndex++) {
+ SECItem **derDpNames = NULL;
+ pkixErrorResult =
+ PKIX_List_GetItem(dpList, dpIndex, (PKIX_PL_Object **)&dp,
+ plContext);
+ if (pkixErrorResult) {
+ PKIX_DECREF(pkixErrorResult);
+ continue;
+ }
+ if (dp->nssdp->distPointType == generalName) {
+ /* dp can only be created from nssdp. */
+ derDpNames = dp->nssdp->derFullName;
+ }
+ while (derDpNames && *derDpNames != NULL) {
+ NamedCRLCacheEntry* cacheEntry = NULL;
+ const SECItem *derDpName = *derDpNames++;
+ rv = cert_FindCRLByGeneralName(nameCrlCache, derDpName,
+ &cacheEntry);
+ if (rv == SECSuccess && cacheEntry) {
+ if ((cacheEntry->inCRLCache &&
+ (cacheEntry->successfulInsertionTime + reloadDelay > time ||
+ (cacheEntry->dupe &&
+ cacheEntry->lastAttemptTime + reloadDelay > time))) ||
+ (cacheEntry->badDER &&
+ cacheEntry->lastAttemptTime + badCrlInvalDelay > time)) {
+ hasFetchedCrlInCache = PKIX_TRUE;
+ break;
+ }
+ }
+ }
+ PKIX_DECREF(dp);
+ }
+cleanup:
+ *pHasFetchedCrlInCache = hasFetchedCrlInCache;
+ if (nameCrlCache) {
+ cert_ReleaseNamedCRLCache(nameCrlCache);
+ }
+ PKIX_DECREF(dpList);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_CheckCrl
+ * DESCRIPTION:
+ *
+ * PARAMETERS:
+ * "params"
+ * Address of the ComCRLSelParams. Must be non-NULL.
+ * "pSelected"
+ * Address at which List will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertStore Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Pk11CertStore_CheckRevByCrl(
+ PKIX_CertStore *store,
+ PKIX_PL_Cert *pkixCert,
+ PKIX_PL_Cert *pkixIssuer,
+ PKIX_PL_Date *date,
+ PKIX_Boolean crlDownloadDone,
+ CERTCRLEntryReasonCode *pReasonCode,
+ PKIX_RevocationStatus *pStatus,
+ void *plContext)
+{
+ PKIX_RevocationStatus pkixRevStatus = PKIX_RevStatus_NoInfo;
+ CERTRevocationStatus revStatus = certRevocationStatusUnknown;
+ PKIX_Boolean hasFetchedCrlInCache = PKIX_TRUE;
+ CERTCertificate *cert = NULL, *issuer = NULL;
+ SECStatus rv = SECSuccess;
+ void *wincx = NULL;
+ PRTime time = 0;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_CheckRevByCrl");
+ PKIX_NULLCHECK_FOUR(store, pkixCert, pkixIssuer, plContext);
+
+ cert = pkixCert->nssCert;
+ issuer = pkixIssuer->nssCert;
+ if (date) {
+ PKIX_CHECK(
+ pkix_pl_Date_GetPRTime(date, &time, plContext),
+ PKIX_DATEGETPRTIMEFAILED);
+ }
+ PKIX_CHECK(
+ pkix_pl_NssContext_GetWincx((PKIX_PL_NssContext*)plContext,
+ &wincx),
+ PKIX_NSSCONTEXTGETWINCXFAILED);
+ /* No need to check any cDPs, since partitioned crls are not
+ * supported. If a ds does not point to partitioned crl, then
+ * the crl should be in issuer cache that is unrelated to any
+ * dp. Using NULL as a dp pointer to check it.*/
+ rv = cert_CheckCertRevocationStatus(cert, issuer, NULL,
+ /* Will not validate the signature
+ * on the crl if time is not specified.*/
+ time, wincx, &revStatus, pReasonCode);
+ if (rv == SECFailure) {
+ pkixRevStatus = PKIX_RevStatus_Revoked;
+ goto cleanup;
+ }
+ if (crlDownloadDone) {
+ if (revStatus == certRevocationStatusRevoked) {
+ pkixRevStatus = PKIX_RevStatus_Revoked;
+ } else if (revStatus == certRevocationStatusValid) {
+ pkixRevStatus = PKIX_RevStatus_Success;
+ }
+ } else {
+ pkixErrorResult =
+ NameCacheHasFetchedCrlInfo(pkixCert, time, &hasFetchedCrlInCache,
+ plContext);
+ if (pkixErrorResult) {
+ goto cleanup;
+ }
+ if (revStatus == certRevocationStatusRevoked &&
+ (hasFetchedCrlInCache ||
+ *pReasonCode != crlEntryReasoncertificatedHold)) {
+ pkixRevStatus = PKIX_RevStatus_Revoked;
+ } else if (revStatus == certRevocationStatusValid &&
+ hasFetchedCrlInCache) {
+ pkixRevStatus = PKIX_RevStatus_Success;
+ }
+ }
+cleanup:
+ *pStatus = pkixRevStatus;
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_GetCert
+ * (see description of PKIX_CertStore_CertCallback in pkix_certstore.h)
+ */
+PKIX_Error *
+pkix_pl_Pk11CertStore_GetCert(
+ PKIX_CertStore *store,
+ PKIX_CertSelector *selector,
+ PKIX_VerifyNode *parentVerifyNode,
+ void **pNBIOContext,
+ PKIX_List **pCertList,
+ void *plContext)
+{
+ PKIX_UInt32 i = 0;
+ PKIX_UInt32 numFound = 0;
+ PKIX_PL_Cert *candidate = NULL;
+ PKIX_List *selected = NULL;
+ PKIX_List *filtered = NULL;
+ PKIX_CertSelector_MatchCallback selectorCallback = NULL;
+ PKIX_CertStore_CheckTrustCallback trustCallback = NULL;
+ PKIX_ComCertSelParams *params = NULL;
+ PKIX_Boolean cacheFlag = PKIX_FALSE;
+ PKIX_VerifyNode *verifyNode = NULL;
+ PKIX_Error *selectorError = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_GetCert");
+ PKIX_NULLCHECK_FOUR(store, selector, pNBIOContext, pCertList);
+
+ *pNBIOContext = NULL; /* We don't use non-blocking I/O */
+
+ PKIX_CHECK(PKIX_CertSelector_GetMatchCallback
+ (selector, &selectorCallback, plContext),
+ PKIX_CERTSELECTORGETMATCHCALLBACKFAILED);
+
+ PKIX_CHECK(PKIX_CertSelector_GetCommonCertSelectorParams
+ (selector, &params, plContext),
+ PKIX_CERTSELECTORGETCOMCERTSELPARAMSFAILED);
+
+ PKIX_CHECK(pkix_pl_Pk11CertStore_CertQuery
+ (params, &selected, plContext),
+ PKIX_PK11CERTSTORECERTQUERYFAILED);
+
+ if (selected) {
+ PKIX_CHECK(PKIX_List_GetLength(selected, &numFound, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+ }
+
+ PKIX_CHECK(PKIX_CertStore_GetCertStoreCacheFlag
+ (store, &cacheFlag, plContext),
+ PKIX_CERTSTOREGETCERTSTORECACHEFLAGFAILED);
+
+ PKIX_CHECK(PKIX_CertStore_GetTrustCallback
+ (store, &trustCallback, plContext),
+ PKIX_CERTSTOREGETTRUSTCALLBACKFAILED);
+
+ PKIX_CHECK(PKIX_List_Create(&filtered, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ for (i = 0; i < numFound; i++) {
+ PKIX_CHECK_ONLY_FATAL(PKIX_List_GetItem
+ (selected,
+ i,
+ (PKIX_PL_Object **)&candidate,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ if (PKIX_ERROR_RECEIVED) {
+ continue; /* just skip bad certs */
+ }
+
+ selectorError =
+ selectorCallback(selector, candidate, plContext);
+ if (!selectorError) {
+ PKIX_CHECK(PKIX_PL_Cert_SetCacheFlag
+ (candidate, cacheFlag, plContext),
+ PKIX_CERTSETCACHEFLAGFAILED);
+
+ if (trustCallback) {
+ PKIX_CHECK(PKIX_PL_Cert_SetTrustCertStore
+ (candidate, store, plContext),
+ PKIX_CERTSETTRUSTCERTSTOREFAILED);
+ }
+
+ PKIX_CHECK_ONLY_FATAL(PKIX_List_AppendItem
+ (filtered,
+ (PKIX_PL_Object *)candidate,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ } else if (parentVerifyNode) {
+ PKIX_CHECK_FATAL(
+ pkix_VerifyNode_Create(candidate, 0, selectorError,
+ &verifyNode, plContext),
+ PKIX_VERIFYNODECREATEFAILED);
+ PKIX_CHECK_FATAL(
+ pkix_VerifyNode_AddToTree(parentVerifyNode,
+ verifyNode,
+ plContext),
+ PKIX_VERIFYNODEADDTOTREEFAILED);
+ PKIX_DECREF(verifyNode);
+ }
+ PKIX_DECREF(selectorError);
+ PKIX_DECREF(candidate);
+ }
+
+ /* Don't throw away the list if one cert was bad! */
+ pkixTempErrorReceived = PKIX_FALSE;
+
+ *pCertList = filtered;
+ filtered = NULL;
+
+cleanup:
+fatal:
+ PKIX_DECREF(filtered);
+ PKIX_DECREF(candidate);
+ PKIX_DECREF(selected);
+ PKIX_DECREF(params);
+ PKIX_DECREF(verifyNode);
+ PKIX_DECREF(selectorError);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+static PKIX_Error *
+RemovePartitionedDpsFromList(PKIX_List *dpList, PKIX_PL_Date *date,
+ void *plContext)
+{
+ NamedCRLCache* nameCrlCache = NULL;
+ pkix_pl_CrlDp *dp = NULL;
+ unsigned int dpIndex = 0;
+ PRTime time;
+ PRTime reloadDelay = 0, badCrlInvalDelay = 0;
+ SECStatus rv;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_ListRemovePrtDp");
+
+ if (!dpList || !dpList->length) {
+ PKIX_RETURN(CERTSTORE);
+ }
+ reloadDelay =
+ ((PKIX_PL_NssContext*)plContext)->crlReloadDelay *
+ PR_USEC_PER_SEC;
+ badCrlInvalDelay =
+ ((PKIX_PL_NssContext*)plContext)->badDerCrlReloadDelay *
+ PR_USEC_PER_SEC;
+ PKIX_CHECK(pkix_pl_Date_GetPRTime(date, &time, plContext),
+ PKIX_DATEGETPRTIMEFAILED);
+ rv = cert_AcquireNamedCRLCache(&nameCrlCache);
+ if (rv == SECFailure) {
+ /* Baling out. Wont find out any thing useful. */
+ PKIX_RETURN(CERTSTORE);
+ }
+ while (dpIndex < dpList->length) {
+ SECItem **derDpNames = NULL;
+ PKIX_Boolean removeDp = PKIX_FALSE;
+
+ PKIX_CHECK(
+ PKIX_List_GetItem(dpList, dpIndex, (PKIX_PL_Object **)&dp,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+ if (!dp->isPartitionedByReasonCode) {
+ /* See if we know about this dp anything why we should
+ * not use it to download a crl. */
+ if (dp->nssdp->distPointType == generalName) {
+ /* dp can only be created from nssdp. */
+ derDpNames = dp->nssdp->derFullName;
+ } else {
+ removeDp = PKIX_TRUE;
+ }
+ while (derDpNames && *derDpNames != NULL) {
+ NamedCRLCacheEntry* cacheEntry = NULL;
+ const SECItem *derDpName = *derDpNames++;
+ /* Removing from the list all dps that we know about. */
+ rv = cert_FindCRLByGeneralName(nameCrlCache, derDpName,
+ &cacheEntry);
+ if (rv && cacheEntry) {
+ if (cacheEntry->unsupported ||
+ (cacheEntry->inCRLCache &&
+ (cacheEntry->successfulInsertionTime + reloadDelay > time ||
+ (cacheEntry->dupe &&
+ cacheEntry->lastAttemptTime + reloadDelay > time))) ||
+ (cacheEntry->badDER &&
+ cacheEntry->lastAttemptTime + badCrlInvalDelay > time)) {
+ removeDp = PKIX_TRUE;
+ }
+ }
+ }
+ } else {
+ /* Remove dp that point to a partitioned crl . RFC 5280
+ * recommends against crl partitioned by reason code.
+ * Will skip such crls */
+ removeDp = PKIX_TRUE;
+ }
+ if (removeDp) {
+ PKIX_CHECK_ONLY_FATAL(
+ pkix_List_Remove(dpList,(PKIX_PL_Object*)dp,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+ } else {
+ dpIndex += 1;
+ }
+ PKIX_DECREF(dp);
+ }
+
+cleanup:
+ if (nameCrlCache) {
+ cert_ReleaseNamedCRLCache(nameCrlCache);
+ }
+ PKIX_DECREF(dp);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_DownloadCrl
+ */
+static PKIX_Error *
+DownloadCrl(pkix_pl_CrlDp *dp, PKIX_PL_CRL **crl,
+ const SEC_HttpClientFcnV1 *hcv1, void *plContext)
+{
+ char *location = NULL;
+ char *hostname = NULL;
+ char *path = NULL;
+ PRUint16 port;
+ SEC_HTTP_SERVER_SESSION pServerSession = NULL;
+ SEC_HTTP_REQUEST_SESSION pRequestSession = NULL;
+ PRUint16 myHttpResponseCode;
+ const char *myHttpResponseData = NULL;
+ PRUint32 myHttpResponseDataLen;
+ SECItem *uri = NULL;
+ SECItem *derCrlCopy = NULL;
+ CERTSignedCrl *nssCrl = NULL;
+ CERTGeneralName *genName = NULL;
+ SECItem **derGenNames = NULL;
+ SECItem *derGenName = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_DownloadCrl");
+
+ /* Do not support dps others than a one with GeneralName
+ * name type. */
+ if (dp->distPointType != generalName ||
+ !dp->nssdp->derFullName) {
+ PKIX_ERROR(PKIX_UNSUPPORTEDCRLDPTYPE);
+ }
+ genName = dp->name.fullName;
+ derGenNames = dp->nssdp->derFullName;
+ do {
+ derGenName = *derGenNames;
+ do {
+ if (!derGenName ||
+ !genName->name.other.data) {
+ /* get to next name if no data. */
+ break;
+ }
+ uri = &genName->name.other;
+ location = (char*)PR_Malloc(1 + uri->len);
+ if (!location) {
+ break;
+ }
+ PORT_Memcpy(location, uri->data, uri->len);
+ location[uri->len] = 0;
+ if (CERT_ParseURL(location, &hostname,
+ &port, &path) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_BAD_CRL_DP_URL);
+ break;
+ }
+
+ PORT_Assert(hostname != NULL);
+ PORT_Assert(path != NULL);
+
+ if ((*hcv1->createSessionFcn)(hostname, port,
+ &pServerSession) != SECSuccess) {
+ PORT_SetError(SEC_ERROR_BAD_CRL_DP_URL);
+ break;
+ }
+
+ if ((*hcv1->createFcn)(pServerSession, "http", path, "GET",
+ /* Users with slow connections might not get CRL revocation
+ checking for certs that use big CRLs because of the timeout
+ We absolutely need code that limits our retry attempts.
+ */
+ PR_SecondsToInterval(
+ ((PKIX_PL_NssContext*)plContext)->timeoutSeconds),
+ &pRequestSession) != SECSuccess) {
+ break;
+ }
+
+ myHttpResponseDataLen =
+ ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
+ if (myHttpResponseDataLen < PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH)
+ myHttpResponseDataLen = PKIX_DEFAULT_MAX_CRL_RESPONSE_LENGTH;
+
+ /* 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
+ */
+ /* we don't want result objects larger than this: */
+ if ((*hcv1->trySendAndReceiveFcn)(
+ pRequestSession,
+ NULL,
+ &myHttpResponseCode,
+ NULL,
+ NULL,
+ &myHttpResponseData,
+ &myHttpResponseDataLen) != SECSuccess) {
+ break;
+ }
+
+ if (myHttpResponseCode != 200) {
+ break;
+ }
+ } while(0);
+ if (!myHttpResponseData) {
+ /* Going to the next one. */
+ genName = CERT_GetNextGeneralName(genName);
+ derGenNames++;
+ }
+ /* Staing in the loop through all the names until
+ * we have a successful download. */
+ } while (!myHttpResponseData && *derGenNames &&
+ genName != dp->name.fullName);
+ /* Need this name to track the crl source location. */
+ PORT_Assert(derGenName);
+
+ if (!myHttpResponseData) {
+ /* Generating fake bad CRL to keep track of this dp */
+ SECItem derCrl = {siBuffer, (void*)"BadCrl", 6 };
+
+ derCrlCopy = SECITEM_DupItem(&derCrl);
+ if (!derCrlCopy) {
+ PKIX_ERROR(PKIX_ALLOCERROR);
+ }
+ derGenName = *dp->nssdp->derFullName;
+ } else {
+ SECItem derCrl = { siBuffer,
+ (void*)myHttpResponseData,
+ myHttpResponseDataLen };
+ derCrlCopy = SECITEM_DupItem(&derCrl);
+ if (!derCrlCopy) {
+ PKIX_ERROR(PKIX_ALLOCERROR);
+ }
+ /* crl will be based on derCrlCopy, but will not own the der. */
+ nssCrl =
+ CERT_DecodeDERCrlWithFlags(NULL, derCrlCopy, SEC_CRL_TYPE,
+ CRL_DECODE_DONT_COPY_DER |
+ CRL_DECODE_SKIP_ENTRIES);
+ }
+ /* pkix crl owns the der. */
+ PKIX_CHECK(
+ pkix_pl_CRL_CreateWithSignedCRL(nssCrl, derCrlCopy,
+ derGenName,
+ crl, plContext),
+ PKIX_CRLCREATEWITHSIGNEDCRLFAILED);
+ /* pkix crl now own both objects. */
+ derCrlCopy = NULL;
+ nssCrl = NULL;
+
+cleanup:
+ if (derCrlCopy)
+ PORT_Free(derCrlCopy);
+ if (nssCrl)
+ SEC_DestroyCrl(nssCrl);
+ if (pRequestSession != NULL)
+ (*hcv1->freeFcn)(pRequestSession);
+ if (pServerSession != NULL)
+ (*hcv1->freeSessionFcn)(pServerSession);
+ if (path != NULL)
+ PORT_Free(path);
+ if (hostname != NULL)
+ PORT_Free(hostname);
+ if (location) {
+ PORT_Free(location);
+ }
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Pk11CertStore_GetCRL
+ * (see description of PKIX_CertStore_CRLCallback in pkix_certstore.h)
+ */
+static PKIX_Error *
+pkix_pl_Pk11CertStore_GetCRL(
+ PKIX_CertStore *store,
+ PKIX_CRLSelector *selector,
+ void **pNBIOContext,
+ PKIX_List **pCrlList,
+ void *plContext)
+{
+ PKIX_UInt32 dpIndex = 0;
+ PKIX_PL_CRL *crl = NULL;
+ PKIX_List *crlList = NULL;
+ PKIX_List *dpList = NULL;
+ pkix_pl_CrlDp *dp = NULL;
+ PKIX_PL_Date *date = NULL;
+ const SEC_HttpClientFcn *registeredHttpClient = NULL;
+
+ PKIX_ENTER(CERTSTORE, "pkix_pl_Pk11CertStore_GetCRL");
+ PKIX_NULLCHECK_THREE(store, pNBIOContext, pCrlList);
+ PKIX_NULLCHECK_TWO(selector, selector->params);
+
+ registeredHttpClient = SEC_GetRegisteredHttpClient();
+ if (!registeredHttpClient || registeredHttpClient->version != 1) {
+ goto cleanup;
+ }
+ dpList = selector->params->crldpList;
+ date = selector->params->date;
+ PKIX_CHECK(
+ RemovePartitionedDpsFromList(dpList, date,
+ plContext),
+ PKIX_FAILTOREMOVEDPFROMLIST);
+ for (;dpIndex < dpList->length;dpIndex++) {
+ PKIX_DECREF(dp);
+ pkixErrorResult =
+ PKIX_List_GetItem(dpList, dpIndex,
+ (PKIX_PL_Object **)&dp,
+ plContext);
+ if (pkixErrorResult) {
+ PKIX_DECREF(pkixErrorResult);
+ continue;
+ }
+ pkixErrorResult =
+ DownloadCrl(dp, &crl,
+ &registeredHttpClient->fcnTable.ftable1,
+ plContext);
+ if (pkixErrorResult || !crl) {
+ /* continue to next dp in case of unsuccesfull
+ * download attempt. */
+ PKIX_DECREF(pkixErrorResult);
+ continue;
+ }
+ if (!crlList) {
+ PKIX_CHECK(PKIX_List_Create(&crlList, plContext),
+ PKIX_LISTCREATEFAILED);
+ }
+ pkixErrorResult =
+ PKIX_List_AppendItem(crlList, (PKIX_PL_Object *)crl,
+ plContext);
+ if (pkixErrorResult) {
+ PKIX_DECREF(pkixErrorResult);
+ }
+ PKIX_DECREF(crl);
+ }
+ *pCrlList = crlList;
+ crlList = NULL;
+
+cleanup:
+ PKIX_DECREF(dp);
+ PKIX_DECREF(crl);
+ PKIX_DECREF(crlList);
+
+ PKIX_RETURN(CERTSTORE);
+}
+
+
+/* --Public-Pk11CertStore-Functions----------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_Pk11CertStore_Create
+ * (see comments in pkix_samples_modules.h)
+ */
+PKIX_Error *
+PKIX_PL_Pk11CertStore_Create(
+ PKIX_CertStore **pCertStore,
+ void *plContext)
+{
+ PKIX_CertStore *certStore = NULL;
+
+ PKIX_ENTER(CERTSTORE, "PKIX_PL_Pk11CertStore_Create");
+ PKIX_NULLCHECK_ONE(pCertStore);
+
+ PKIX_CHECK(PKIX_CertStore_Create
+ (pkix_pl_Pk11CertStore_GetCert,
+ pkix_pl_Pk11CertStore_GetCRL,
+ NULL, /* getCertContinue */
+ NULL, /* getCrlContinue */
+ pkix_pl_Pk11CertStore_CheckTrust,
+ pkix_pl_Pk11CertStore_ImportCrl,
+ pkix_pl_Pk11CertStore_CheckRevByCrl,
+ NULL,
+ PKIX_TRUE, /* cache flag */
+ PKIX_TRUE, /* local - no network I/O */
+ &certStore,
+ plContext),
+ PKIX_CERTSTORECREATEFAILED);
+
+ *pCertStore = certStore;
+
+cleanup:
+
+ PKIX_RETURN(CERTSTORE);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.h
new file mode 100755
index 000000000..506707683
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_pk11certstore.h
@@ -0,0 +1,31 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_pk11certstore.h
+ *
+ * PK11Certstore Object Type Definition
+ *
+ */
+
+#ifndef _PKIX_PL_PK11CERTSTORE_H
+#define _PKIX_PL_PK11CERTSTORE_H
+
+#include "pkix_pl_common.h"
+#include "certi.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* see source file for function documentation */
+PKIX_Error *
+PKIX_PL_Pk11CertStore_Create(
+ PKIX_CertStore **pCertStore,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_PK11CERTSTORE_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c
new file mode 100644
index 000000000..e8698376b
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.c
@@ -0,0 +1,1695 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_socket.c
+ *
+ * Socket Function Definitions
+ *
+ */
+
+/*
+ * If Socket Tracing is active, messages sent and received will be
+ * timestamped and dumped (to stdout) in standard hex-dump format. E.g.,
+ *
+ * 1116612359156140:
+ * 28F0: 48 65 6C 6C 6F 2C 20 77 6F 72 6C 64 21 00 Hello, world!.
+ *
+ * The timestamp is not formatted to be meaningful except as an increasing
+ * value of seconds.microseconds, which is good enough to correlate two
+ * sides of a message exchange and to figure durations.
+ *
+ * Code to perform Socket tracing will be compiled in if PKIX_SOCKETTRACE
+ * is defined, but that doesn't mean socket tracing is active. Tracing also
+ * requires that the Boolean socketTraceFlag is set to PKIX_TRUE. That is
+ * the default value, but it can be overridden by using the debugger to
+ * change its value -- allowing tracing to be turned on and off at various
+ * breakpoints -- or by setting the environment variable SOCKETTRACE. A
+ * value of 1 sets socketTraceFlag to PKIX_TRUE (tracing on), and any other
+ * value sets socketTraceFlag to PKIX_FALSE (tracing off). The environment
+ * value is checked during system initialization.
+ */
+#ifndef BUILD_OPT
+#define PKIX_SOCKETTRACE 1
+#endif
+
+#ifdef PKIX_SOCKETDEBUG
+#define PKIX_SOCKETTRACE 1
+#endif
+
+#include "pkix_pl_socket.h"
+
+/* --Private-Socket-Functions---------------------------------- */
+
+#ifdef PKIX_SOCKETTRACE
+static PKIX_Boolean socketTraceFlag = PKIX_FALSE;
+
+/*
+ * FUNCTION: pkix_pl_socket_timestamp
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the time of day, as obtained from the
+ * system function gettimeofday, as seconds.microseconds. Its resolution
+ * is whatever the system call provides.
+ *
+ * PARAMETERS:
+ * none
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static void pkix_pl_socket_timestamp() {
+ PRInt64 prTime;
+ prTime = PR_Now();
+/* We shouldn't use PR_ALTERNATE_INT64_TYPEDEF, but nor can we use PRId64 */
+#if PR_BYTES_PER_LONG == 8 && !defined(PR_ALTERNATE_INT64_TYPEDEF)
+ printf("%ld:\n", prTime);
+#else
+ printf("%lld:\n", prTime);
+#endif
+}
+
+/*
+ * FUNCTION: pkix_pl_socket_hexDigit
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the byte "byteVal" as two hex digits.
+ *
+ * PARAMETERS:
+ * "byteVal"
+ * The value to be printed.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static void pkix_pl_socket_hexDigit(char byteVal) {
+ int n = 0;
+ char cHi = '\0';
+ char cLow = '\0';
+ n = ((byteVal >> 4) & 0xf);
+ if (n > 9) {
+ cHi = (char) ((n - 10) + 'A');
+ } else {
+ cHi = (char) (n + '0');
+ }
+ n = byteVal & 0xf;
+ if (n > 9) {
+ cLow = (char) ((n - 10) + 'A');
+ } else {
+ cLow = (char) (n + '0');
+ }
+ (void) printf("%c%c", cHi, cLow);
+}
+
+/*
+ * FUNCTION: pkix_pl_socket_linePrefix
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the address provided by "addr" as four
+ * hexadecimal digits followed by a colon and a space.
+ *
+ * PARAMETERS:
+ * "addr"
+ * The address to be printed
+ * none
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static void pkix_pl_socket_linePrefix(PKIX_UInt32 addr) {
+ pkix_pl_socket_hexDigit((char)((addr >> 8) & 0xff));
+ pkix_pl_socket_hexDigit((char)(addr & 0xff));
+ (void) printf(": ");
+}
+
+/*
+ * FUNCTION: pkix_pl_socket_traceLine
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the sixteen bytes beginning at the
+ * address pointed to by "ptr". The bytes are printed as sixteen pairs
+ * of hexadecimal characters followed by an ascii interpretation, in which
+ * characters from 0x20 to 0x7d are shown as their ascii equivalents, and
+ * other values are represented as periods.
+ *
+ * PARAMETERS:
+ * "ptr"
+ * The address of the first of the bytes to be printed
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static void pkix_pl_socket_traceLine(char *ptr) {
+ PKIX_UInt32 i = 0;
+ pkix_pl_socket_linePrefix((PKIX_UInt32)((char *)ptr - (char *)NULL));
+ for (i = 0; i < 16; i++) {
+ printf(" ");
+ pkix_pl_socket_hexDigit(ptr[i]);
+ if (i == 7) {
+ printf(" ");
+ }
+ }
+ printf(" ");
+ for (i = 0; i < 16; i++) {
+ if ((ptr[i] < ' ') || (ptr[i] > '}')) {
+ printf(".");
+ } else {
+ printf("%c", ptr[i]);
+ }
+ }
+ printf("\n");
+}
+
+/*
+ * FUNCTION: pkix_pl_socket_tracePartialLine
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the number of bytes given by "nBytes",
+ * beginning at the address pointed to by "ptr". The bytes are printed as
+ * pairs of hexadecimal characters followed by an ascii interpretation, in
+ * which characters from 0x20 to 0x7d are shown as their ascii equivalents,
+ * and other values are represented as periods.
+ *
+ * PARAMETERS:
+ * "ptr"
+ * The address of the first of the bytes to be printed
+ * "nBytes"
+ * The Int32 value giving the number of bytes to be printed. If "nBytes"
+ * is greater than sixteen, the results will be unattractive.
+ * none
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static void pkix_pl_socket_tracePartialLine(char *ptr, PKIX_UInt32 nBytes) {
+ PKIX_UInt32 i = 0;
+ if (nBytes > 0) {
+ pkix_pl_socket_linePrefix((PKIX_UInt32)((char *)ptr - (char *)NULL));
+ }
+ for (i = 0; i < nBytes; i++) {
+ printf(" ");
+ pkix_pl_socket_hexDigit(ptr[i]);
+ if (i == 7) {
+ printf(" ");
+ }
+ }
+ for (i = nBytes; i < 16; i++) {
+ printf(" ");
+ if (i == 7) {
+ printf(" ");
+ }
+ }
+ printf(" ");
+ for (i = 0; i < nBytes; i++) {
+ if ((ptr[i] < ' ') || (ptr[i] > '}')) {
+ printf(".");
+ } else {
+ printf("%c", ptr[i]);
+ }
+ }
+ printf("\n");
+}
+
+/*
+ * FUNCTION: pkix_pl_socket_tracebuff
+ * DESCRIPTION:
+ *
+ * This functions prints to stdout the number of bytes given by "nBytes",
+ * beginning with the byte pointed to by "buf". The output is preceded by
+ * a timestamp, and each group of sixteen (and a remainder, if any) is
+ * preceded by its address. The contents are shown in hexadecimal and as
+ * ascii characters. If "nBytes" is zero, the timestamp and starting
+ * address are displayed.
+ *
+ * PARAMETERS:
+ * "buf"
+ * The starting address of the bytes to be printed
+ * "nBytes"
+ * The number of bytes to be printed
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+void pkix_pl_socket_tracebuff(void *buf, PKIX_UInt32 nBytes) {
+ PKIX_UInt32 bytesRemaining = nBytes;
+ PKIX_UInt32 offset = 0;
+ char *bufptr = (char *)buf;
+
+ if (socketTraceFlag == PKIX_FALSE) return;
+
+ pkix_pl_socket_timestamp();
+ /*
+ * Special case: if called with length of zero, just do address
+ */
+ if (nBytes == 0) {
+ pkix_pl_socket_linePrefix((PKIX_UInt32)((char *)buf - (char *)NULL));
+ printf("\n");
+ } else {
+ while (bytesRemaining >= 16) {
+ pkix_pl_socket_traceLine(&bufptr[offset]);
+ bytesRemaining -= 16;
+ offset += 16;
+ }
+ pkix_pl_socket_tracePartialLine
+ (&bufptr[offset], bytesRemaining);
+ }
+}
+
+#endif
+
+/*
+ * FUNCTION: pkix_pl_Socket_SetNonBlocking
+ * DESCRIPTION:
+ *
+ * This functions sets the socket represented by the PRFileDesc "fileDesc"
+ * to nonblocking mode.
+ *
+ * PARAMETERS:
+ * "fileDesc"
+ * The address of the PRFileDesc whose I/O mode is to be set
+ * non-blocking. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_SetNonBlocking(
+ PRFileDesc *fileDesc,
+ void *plContext)
+{
+ PRStatus rv = PR_FAILURE;
+ PRSocketOptionData sockOptionData;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_SetNonBlocking");
+ PKIX_NULLCHECK_ONE(fileDesc);
+
+ sockOptionData.option = PR_SockOpt_Nonblocking;
+ sockOptionData.value.non_blocking = PR_TRUE;
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, fileDesc->methods->setsocketoption,
+ (fileDesc, &sockOptionData));
+
+ if (rv != PR_SUCCESS) {
+ PKIX_ERROR(PKIX_UNABLETOSETSOCKETTONONBLOCKING);
+ }
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_CreateClient
+ * DESCRIPTION:
+ *
+ * This functions creates a client socket for the PKIX_PL_Socket pointed to
+ * by "socket". If "socket" was created with a timeout value of zero, the
+ * client socket is set to use nonblocking I/O.
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the Socket for which a client socket is to be
+ * created. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+
+static PKIX_Error *
+pkix_pl_Socket_CreateClient(
+ PKIX_PL_Socket *socket,
+ void *plContext)
+{
+#ifdef PKIX_SOCKETDEBUG
+ PRErrorCode errorcode = 0;
+#endif
+ PRFileDesc *mySock = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateClient");
+ PKIX_NULLCHECK_ONE(socket);
+
+ PKIX_PL_NSSCALLRV(SOCKET, mySock, PR_NewTCPSocket, ());
+ if (!mySock) {
+#ifdef PKIX_SOCKETDEBUG
+ errorcode = PR_GetError();
+ printf
+ ("pkix_pl_Socket_CreateClient: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED);
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Created socket, PRFileDesc @ %#X\n", mySock);
+#endif
+
+ socket->clientSock = mySock;
+ socket->status = SOCKET_UNCONNECTED;
+ if (socket->timeout == 0) {
+ PKIX_CHECK(pkix_pl_Socket_SetNonBlocking(mySock, plContext),
+ PKIX_SOCKETSETNONBLOCKINGFAILED);
+ }
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_CreateServer
+ * DESCRIPTION:
+ *
+ * This functions creates a server socket for the PKIX_PL_Socket pointed to
+ * by "socket". If "socket" was created with a timeout value of zero, the
+ * server socket is set to use nonblocking I/O.
+ *
+ * Warning: there seems to be a problem with operating a server socket in
+ * non-blocking mode. If the server calls Recv prior to a corresponding
+ * Send, the message may be lost.
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the Socket for which a server socket is to be
+ * created. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_CreateServer(
+ PKIX_PL_Socket *socket,
+ void *plContext)
+{
+/* #ifdef PKIX_SOCKETDEBUG */
+ PRErrorCode errorcode = 0;
+/* #endif */
+ PRStatus rv = PR_FAILURE;
+ PRFileDesc *serverSock = NULL;
+ PRSocketOptionData sockOptionData;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateServer");
+ PKIX_NULLCHECK_ONE(socket);
+
+ PKIX_PL_NSSCALLRV(SOCKET, serverSock, PR_NewTCPSocket, ());
+ if (!serverSock) {
+#ifdef PKIX_SOCKETDEBUG
+ errorcode = PR_GetError();
+ printf
+ ("pkix_pl_Socket_CreateServer: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRNEWTCPSOCKETFAILED);
+ }
+
+ socket->serverSock = serverSock;
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Created socket, PRFileDesc @ %#X\n", serverSock);
+#endif
+
+ if (socket->timeout == 0) {
+ PKIX_CHECK(pkix_pl_Socket_SetNonBlocking(serverSock, plContext),
+ PKIX_SOCKETSETNONBLOCKINGFAILED);
+ }
+
+ sockOptionData.option = PR_SockOpt_Reuseaddr;
+ sockOptionData.value.reuse_addr = PR_TRUE;
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, serverSock->methods->setsocketoption,
+ (serverSock, &sockOptionData));
+
+ if (rv != PR_SUCCESS) {
+ PKIX_ERROR(PKIX_UNABLETOSETSOCKETTONONBLOCKING);
+ }
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Bind, (serverSock, socket->netAddr));
+
+ if (rv == PR_FAILURE) {
+/* #ifdef PKIX_SOCKETDEBUG */
+ errorcode = PR_GetError();
+ printf
+ ("pkix_pl_Socket_CreateServer: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+/* #endif */
+ PKIX_ERROR(PKIX_PRBINDFAILED);
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Successful bind!\n");
+#endif
+
+ socket->status = SOCKET_BOUND;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Connect
+ * DESCRIPTION:
+ *
+ * This functions performs the connect function for the client socket
+ * specified in "socket", storing the status at "pStatus".
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the Socket for which a connect is to be performed.
+ * Must be non-NULL.
+ * "pStatus"
+ * The address at which the connection status is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Connect(
+ PKIX_PL_Socket *socket,
+ PRErrorCode *pStatus,
+ void *plContext)
+{
+ PRStatus rv = PR_FAILURE;
+ PRErrorCode errorcode = 0;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Connect");
+ PKIX_NULLCHECK_TWO(socket, socket->clientSock);
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Connect,
+ (socket->clientSock, socket->netAddr, socket->timeout));
+
+ if (rv == PR_FAILURE) {
+ errorcode = PR_GetError();
+ *pStatus = errorcode;
+ if (errorcode == PR_IN_PROGRESS_ERROR) {
+ socket->status = SOCKET_CONNECTPENDING;
+ goto cleanup;
+ } else {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_Connect: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRCONNECTFAILED);
+ }
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Successful connect!\n");
+#endif
+
+ *pStatus = 0;
+ socket->status = SOCKET_CONNECTED;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_ConnectContinue
+ * DESCRIPTION:
+ *
+ * This functions continues the connect function for the client socket
+ * specified in "socket", storing the status at "pStatus". It is expected that
+ * the non-blocking connect has returned PR_IN_PROGRESS_ERROR.
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the Socket for which a connect is to be continued.
+ * Must be non-NULL.
+ * "pStatus"
+ * The address at which the connection status is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_ConnectContinue(
+ PKIX_PL_Socket *socket,
+ PRErrorCode *pStatus,
+ void *plContext)
+{
+ PRStatus rv = PR_FAILURE;
+ PRErrorCode errorcode = 0;
+ PRPollDesc pollDesc;
+ PRInt32 numEvents = 0;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_ConnectContinue");
+ PKIX_NULLCHECK_TWO(socket, socket->clientSock);
+
+ pollDesc.fd = socket->clientSock;
+ pollDesc.in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT;
+ pollDesc.out_flags = 0;
+ PKIX_PL_NSSCALLRV(SOCKET, numEvents, PR_Poll, (&pollDesc, 1, 0));
+ if (numEvents < 0) {
+ PKIX_ERROR(PKIX_PRPOLLFAILED);
+ }
+
+ if (numEvents == 0) {
+ *pStatus = PR_IN_PROGRESS_ERROR;
+ goto cleanup;
+ }
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, PR_ConnectContinue,
+ (socket->clientSock, pollDesc.out_flags));
+
+ /*
+ * PR_ConnectContinue sometimes lies. It returns PR_SUCCESS
+ * even though the connection is not yet ready. But its deceit
+ * is betrayed by the contents of out_flags!
+ */
+ if ((rv == PR_SUCCESS) && (pollDesc.out_flags == PR_POLL_ERR)) {
+ *pStatus = PR_IN_PROGRESS_ERROR;
+ goto cleanup;
+ }
+
+ if (rv == PR_FAILURE) {
+ errorcode = PR_GetError();
+ *pStatus = errorcode;
+ if (errorcode == PR_IN_PROGRESS_ERROR) {
+ goto cleanup;
+ } else {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_ConnectContinue: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRCONNECTCONTINUEFAILED);
+ }
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Successful connect!\n");
+#endif
+
+ *pStatus = 0;
+ socket->status = SOCKET_CONNECTED;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Socket_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_Socket *socket = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_SOCKET_TYPE, plContext),
+ PKIX_OBJECTNOTANSOCKET);
+
+ socket = (PKIX_PL_Socket *)object;
+
+ if (socket->isServer) {
+ if (socket->serverSock) {
+ PR_Close(socket->serverSock);
+ }
+ } else {
+ if (socket->clientSock) {
+ PR_Close(socket->clientSock);
+ }
+ }
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Socket_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_Socket *socket = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_SOCKET_TYPE, plContext),
+ PKIX_OBJECTNOTSOCKET);
+
+ socket = (PKIX_PL_Socket *)object;
+
+ *pHashcode = (((socket->timeout << 3) +
+ (socket->netAddr->inet.family << 3)) +
+ (*((PKIX_UInt32 *)&(socket->netAddr->inet.ip)))) +
+ socket->netAddr->inet.port;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Equals
+ * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Socket_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Int32 *pResult,
+ void *plContext)
+{
+ PKIX_PL_Socket *firstSocket = NULL;
+ PKIX_PL_Socket *secondSocket = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ *pResult = PKIX_FALSE;
+
+ PKIX_CHECK(pkix_CheckTypes
+ (firstObject, secondObject, PKIX_SOCKET_TYPE, plContext),
+ PKIX_OBJECTNOTSOCKET);
+
+ firstSocket = (PKIX_PL_Socket *)firstObject;
+ secondSocket = (PKIX_PL_Socket *)secondObject;
+
+ if (firstSocket->timeout != secondSocket->timeout) {
+ goto cleanup;
+ }
+
+ if (firstSocket->netAddr == secondSocket->netAddr) {
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ if ((firstSocket->netAddr->inet.family !=
+ secondSocket->netAddr->inet.family) ||
+ (*((PKIX_UInt32 *)&(firstSocket->netAddr->inet.ip)) !=
+ *((PKIX_UInt32 *)&(secondSocket->netAddr->inet.ip))) ||
+ (firstSocket->netAddr->inet.port !=
+ secondSocket->netAddr->inet.port)) {
+
+ goto cleanup;
+
+ }
+
+ *pResult = PKIX_TRUE;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_RegisterSelf
+ *
+ * DESCRIPTION:
+ * Registers PKIX_PL_SOCKET_TYPE and its related
+ * functions with systemClasses[]
+ *
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_Socket_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_RegisterSelf");
+
+ entry.description = "Socket";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_Socket);
+ entry.destructor = pkix_pl_Socket_Destroy;
+ entry.equalsFunction = pkix_pl_Socket_Equals;
+ entry.hashcodeFunction = pkix_pl_Socket_Hashcode;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = NULL;
+
+ systemClasses[PKIX_SOCKET_TYPE] = entry;
+
+#ifdef PKIX_SOCKETTRACE
+ {
+ char *val = NULL;
+ val = PR_GetEnvSecure("SOCKETTRACE");
+ /* Is SOCKETTRACE set in the environment? */
+ if ((val != NULL) && (*val != '\0')) {
+ socketTraceFlag =
+ ((*val == '1')?PKIX_TRUE:PKIX_FALSE);
+ }
+ }
+#endif
+
+ PKIX_RETURN(SOCKET);
+}
+
+/* --Public-Socket-Functions----------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_Socket_Listen
+ * DESCRIPTION:
+ *
+ * This functions establishes a listening queue for the server Socket
+ * pointed to by "socket".
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the server socket for which the queue is to be
+ * established. Must be non-NULL.
+ * "backlog"
+ * The UInt32 value of the length of the queue to be established.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Listen(
+ PKIX_PL_Socket *socket,
+ PKIX_UInt32 backlog,
+ void *plContext)
+{
+#ifdef PKIX_SOCKETDEBUG
+ PRErrorCode errorcode = 0;
+#endif
+ PRStatus rv = PR_FAILURE;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Listen");
+ PKIX_NULLCHECK_TWO(socket, socket->serverSock);
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Listen,
+ (socket->serverSock, (PRIntn)backlog));
+
+ if (rv == PR_FAILURE) {
+#ifdef PKIX_SOCKETDEBUG
+ errorcode = PR_GetError();
+ printf
+ ("pkix_pl_Socket_Listen: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRLISTENFAILED);
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Successful listen!\n");
+#endif
+
+ socket->status = SOCKET_LISTENING;
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Shutdown
+ * DESCRIPTION:
+ *
+ * This functions performs the shutdown of any connections controlled by the
+ * socket pointed to by "socket".
+ *
+ * PARAMETERS:
+ * "socket"
+ * The address of the socket to be shut down. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Shutdown(
+ PKIX_PL_Socket *socket,
+ void *plContext)
+{
+#ifdef PKIX_SOCKETDEBUG
+ PRErrorCode errorcode = 0;
+#endif
+ PRStatus rv = PR_FAILURE;
+ PRFileDesc *fileDesc = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Shutdown");
+ PKIX_NULLCHECK_ONE(socket);
+
+ fileDesc =
+ (socket->isServer)?(socket->serverSock):(socket->clientSock);
+
+ PKIX_PL_NSSCALLRV(SOCKET, rv, PR_Shutdown,
+ (fileDesc, PR_SHUTDOWN_BOTH));
+
+ if (rv == PR_FAILURE) {
+#ifdef PKIX_SOCKETDEBUG
+ errorcode = PR_GetError();
+ printf
+ ("pkix_pl_Socket_Shutdown: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRSHUTDOWNFAILED);
+ }
+ socket->status = SOCKET_SHUTDOWN;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Send
+ * DESCRIPTION:
+ *
+ * This functions sends a message using the socket pointed to by "sendSock",
+ * from the buffer pointed to by "buf", of the number of bytes given by
+ * "bytesToWrite", storing the number of bytes actually written at
+ * "pBytesWritten". If "socket" is in non-blocking mode, the send operation
+ * may store -1 at "pBytesWritten" and the write is not complete until a
+ * corresponding pkix_pl_Poll call has indicated its completion by returning
+ * a non-negative value for bytes written.
+ *
+ * PARAMETERS:
+ * "sendSock"
+ * The address of the Socket on which the message is to be sent. Must
+ * be non-NULL.
+ * "buf"
+ * The address of the data to be sent. Must be non-NULL.
+ * "bytesToWrite""
+ * The UInt32 value indicating the number of bytes to write.
+ * "pBytesWritten"
+ * The address at which the Int32 value indicating the number of bytes
+ * actually written is to be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Send(
+ PKIX_PL_Socket *sendSock,
+ void *buf,
+ PKIX_UInt32 bytesToWrite,
+ PKIX_Int32 *pBytesWritten,
+ void *plContext)
+{
+ PRInt32 bytesWritten = 0;
+ PRErrorCode errorcode = 0;
+ PRFileDesc *fd = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Send");
+ PKIX_NULLCHECK_TWO(buf, pBytesWritten);
+
+ fd = sendSock->clientSock;
+
+ PKIX_PL_NSSCALLRV(SOCKET, bytesWritten, PR_Send,
+ (fd, buf, (PRInt32)bytesToWrite, 0, sendSock->timeout));
+
+ if (bytesWritten >= 0) {
+ if (sendSock->status == SOCKET_SENDRCVPENDING) {
+ sendSock->status = SOCKET_RCVPENDING;
+ } else {
+ sendSock->status = SOCKET_CONNECTED;
+ }
+#ifdef PKIX_SOCKETTRACE
+ pkix_pl_socket_tracebuff(buf, bytesWritten);
+#endif
+ } else {
+ errorcode = PR_GetError();
+ if (errorcode != PR_WOULD_BLOCK_ERROR) {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_Send: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRSENDFAILED);
+ }
+
+ sendSock->writeBuf = buf;
+ sendSock->writeBufSize = bytesToWrite;
+ if (sendSock->status == SOCKET_RCVPENDING) {
+ sendSock->status = SOCKET_SENDRCVPENDING;
+ } else {
+ sendSock->status = SOCKET_SENDPENDING;
+ }
+ }
+
+ *pBytesWritten = (PKIX_Int32)bytesWritten;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Recv
+ * DESCRIPTION:
+ *
+ * This functions receives a message on the socket pointed to by "rcvSock",
+ * into the buffer pointed to by "buf", of capacity given by "capacity",
+ * storing the number of bytes actually received at "pBytesRead". If "socket"
+ * is in non-blocking mode, the receive operation may store -1 at
+ * "pBytesWritten". In that case the write is not complete until a
+ * corresponding pkix_pl_Poll call has indicated its completion by returning
+ * a non-negative value for bytes read.
+ *
+ * PARAMETERS:
+ * "rcvSock"
+ * The address of the Socket on which the message is to be received.
+ * Must be non-NULL.
+ * "buf"
+ * The address of the buffer into which the message is to be received.
+ * Must be non-NULL.
+ * "capacity"
+ * The UInt32 value of the size of the buffer; that is, the maximum
+ * number of bytes that can be received.
+ * "pBytesRead"
+ * The address at which is stored the Int32 value of the number of bytes
+ * actually received.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Recv(
+ PKIX_PL_Socket *rcvSock,
+ void *buf,
+ PKIX_UInt32 capacity,
+ PKIX_Int32 *pBytesRead,
+ void *plContext)
+{
+ PRErrorCode errorcode = 0;
+ PRInt32 bytesRead = 0;
+ PRFileDesc *fd = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Recv");
+ PKIX_NULLCHECK_THREE(rcvSock, buf, pBytesRead);
+
+ fd = rcvSock->clientSock;
+
+ PKIX_PL_NSSCALLRV(SOCKET, bytesRead, PR_Recv,
+ (fd, buf, (PRInt32)capacity, 0, rcvSock->timeout));
+
+ if (bytesRead > 0) {
+ if (rcvSock->status == SOCKET_SENDRCVPENDING) {
+ rcvSock->status = SOCKET_SENDPENDING;
+ } else {
+ rcvSock->status = SOCKET_CONNECTED;
+ }
+#ifdef PKIX_SOCKETTRACE
+ pkix_pl_socket_tracebuff(buf, bytesRead);
+#endif
+ } else if (bytesRead == 0) {
+ PKIX_ERROR(PKIX_PRRECVREPORTSNETWORKCONNECTIONCLOSED);
+ } else {
+ errorcode = PR_GetError();
+ if (errorcode != PR_WOULD_BLOCK_ERROR) {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_Recv: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRRECVFAILED);
+ }
+ rcvSock->readBuf = buf;
+ rcvSock->readBufSize = capacity;
+ if (rcvSock->status == SOCKET_SENDPENDING) {
+ rcvSock->status = SOCKET_SENDRCVPENDING;
+ } else {
+ rcvSock->status = SOCKET_RCVPENDING;
+ }
+
+ }
+
+ *pBytesRead = (PKIX_Int32)bytesRead;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Poll
+ * DESCRIPTION:
+ *
+ * This functions checks for completion of an earlier Send or Recv on the
+ * socket pointed to by "sock", storing in "pBytesWritten" the number of bytes
+ * written by a completed Send and in "pBytesRead" the number of bytes
+ * received in a completed Recv. A value of -1 returned indicates the
+ * operation has still not completed. A NULL pointer may be supplied for
+ * "pBytesWritten" to avoid checking for completion of a Send. A NULL pointer
+ * may be supplied for "pBytesRead" to avoid checking for completion of a Recv.
+ *
+ * PARAMETERS:
+ * "sock"
+ * The address of the socket for which completions are to be checked.
+ * "pBytesWritten"
+ * The address at which the number of bytes written is to be stored, if
+ * a pending Send has completed. If NULL, Sends are not checked.
+ * "pBytesRead"
+ * The address at which the number of bytes read is to be stored, if
+ * a pending Recv has completed. If NULL, Recvs are not checked.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Poll(
+ PKIX_PL_Socket *sock,
+ PKIX_Int32 *pBytesWritten,
+ PKIX_Int32 *pBytesRead,
+ void *plContext)
+{
+ PRPollDesc pollDesc;
+ PRInt32 numEvents = 0;
+ PKIX_Int32 bytesRead = 0;
+ PKIX_Int32 bytesWritten = 0;
+ PRErrorCode errorcode = 0;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Poll");
+ PKIX_NULLCHECK_ONE(sock);
+
+ pollDesc.fd = sock->clientSock;
+ pollDesc.in_flags = 0;
+ pollDesc.out_flags = 0;
+
+ if ((pBytesWritten) &&
+ ((sock->status == SOCKET_SENDPENDING) ||
+ (sock->status == SOCKET_SENDRCVPENDING))) {
+ pollDesc.in_flags = PR_POLL_WRITE;
+ }
+
+ if ((pBytesRead) &&
+ ((sock->status == SOCKET_RCVPENDING) ||
+ (sock->status == SOCKET_SENDRCVPENDING))) {
+ pollDesc.in_flags |= PR_POLL_READ;
+ }
+
+ PKIX_PL_NSSCALLRV(SOCKET, numEvents, PR_Poll, (&pollDesc, 1, 0));
+
+ if (numEvents < 0) {
+ PKIX_ERROR(PKIX_PRPOLLFAILED);
+ } else if (numEvents > 0) {
+ if (pollDesc.out_flags & PR_POLL_WRITE) {
+ PKIX_CHECK(pkix_pl_Socket_Send
+ (sock,
+ sock->writeBuf,
+ sock->writeBufSize,
+ &bytesWritten,
+ plContext),
+ PKIX_SOCKETSENDFAILED);
+ *pBytesWritten = (PKIX_Int32)bytesWritten;
+ if (bytesWritten >= 0) {
+ sock->writeBuf = NULL;
+ sock->writeBufSize = 0;
+ }
+ }
+
+ if (pollDesc.out_flags & PR_POLL_READ) {
+ PKIX_CHECK(pkix_pl_Socket_Recv
+ (sock,
+ sock->readBuf,
+ sock->readBufSize,
+ &bytesRead,
+ plContext),
+ PKIX_SOCKETRECVFAILED);
+ *pBytesRead = (PKIX_Int32)bytesRead;
+ if (bytesRead >= 0) {
+ sock->readBuf = NULL;
+ sock->readBufSize = 0;
+ }
+ }
+ } else if (numEvents == 0) {
+ errorcode = PR_GetError();
+ if (errorcode != PR_WOULD_BLOCK_ERROR) {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_Poll: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRPOLLFAILED);
+ }
+ if (pBytesWritten) {
+ *pBytesWritten = 0;
+ }
+ if (pBytesRead) {
+ *pBytesRead = 0;
+ }
+ }
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Accept
+ * DESCRIPTION:
+ *
+ * This functions accepts a client connection for the server Socket pointed
+ * to by "serverSocket", creating a new Socket and storing the result at
+ * "pRendezvousSocket". If "serverSocket" is in non-blocking mode, this
+ * function will return NULL if there is no client connection to accept.
+ * Otherwise this function will block until a connection is available.
+ * When a client connection is available the new Socket will have the same
+ * blocking/non-blocking property as "serverSocket".
+ *
+ * PARAMETERS:
+ * "serverSocket"
+ * The address of the Socket for which a client connection is to be
+ * accepted. Must be non-NULL.
+ * "pRendezvousSocket"
+ * The address at which the created Socket is stored, when a client
+ * connection is available, or at which NULL is stored, if no connection
+ * is available for a non-blocking "serverSocket". Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety definitions in Programmer's Guide)
+ * RETURNS:
+ * none
+ */
+static PKIX_Error *
+pkix_pl_Socket_Accept(
+ PKIX_PL_Socket *serverSocket,
+ PKIX_PL_Socket **pRendezvousSocket,
+ void *plContext)
+{
+ PRErrorCode errorcode = 0;
+ PRFileDesc *rendezvousSock = NULL;
+ PRNetAddr *clientAddr = NULL;
+ PKIX_PL_Socket *newSocket = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Accept");
+ PKIX_NULLCHECK_TWO(serverSocket, pRendezvousSocket);
+
+ PKIX_PL_NSSCALLRV(SOCKET, rendezvousSock, PR_Accept,
+ (serverSocket->serverSock, clientAddr, serverSocket->timeout));
+
+ if (!rendezvousSock) {
+ errorcode = PR_GetError();
+ if (errorcode != PR_WOULD_BLOCK_ERROR) {
+#ifdef PKIX_SOCKETDEBUG
+ printf
+ ("pkix_pl_Socket_Accept: %s\n",
+ PR_ErrorToString(errorcode, PR_LANGUAGE_EN));
+#endif
+ PKIX_ERROR(PKIX_PRACCEPTFAILED);
+ }
+ serverSocket->status = SOCKET_ACCEPTPENDING;
+ *pRendezvousSocket = NULL;
+ goto cleanup;
+
+ }
+
+#ifdef PKIX_SOCKETDEBUG
+ printf("Successful accept!\n");
+#endif
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_SOCKET_TYPE,
+ sizeof (PKIX_PL_Socket),
+ (PKIX_PL_Object **)&newSocket,
+ plContext),
+ PKIX_COULDNOTCREATESOCKETOBJECT);
+
+ newSocket->isServer = PKIX_FALSE;
+ newSocket->timeout = serverSocket->timeout;
+ newSocket->clientSock = rendezvousSock;
+ newSocket->serverSock = NULL;
+ newSocket->netAddr = NULL;
+ newSocket->status = SOCKET_CONNECTED;
+ newSocket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown;
+ newSocket->callbackList.listenCallback = pkix_pl_Socket_Listen;
+ newSocket->callbackList.acceptCallback = pkix_pl_Socket_Accept;
+ newSocket->callbackList.connectcontinueCallback =
+ pkix_pl_Socket_ConnectContinue;
+ newSocket->callbackList.sendCallback = pkix_pl_Socket_Send;
+ newSocket->callbackList.recvCallback = pkix_pl_Socket_Recv;
+ newSocket->callbackList.pollCallback = pkix_pl_Socket_Poll;
+
+ if (serverSocket->timeout == 0) {
+ PKIX_CHECK(pkix_pl_Socket_SetNonBlocking
+ (rendezvousSock, plContext),
+ PKIX_SOCKETSETNONBLOCKINGFAILED);
+ }
+
+ *pRendezvousSocket = newSocket;
+
+cleanup:
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_Create
+ * DESCRIPTION:
+ *
+ * This function creates a new Socket, setting it to be a server or a client
+ * according to the value of "isServer", setting its timeout value from
+ * "timeout" and server address from "netAddr", and stores the created Socket
+ * at "pSocket".
+ *
+ * PARAMETERS:
+ * "isServer"
+ * The Boolean value indicating if PKIX_TRUE, that a server socket (using
+ * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a
+ * client socket (using Connect) is to be created.
+ * "timeout"
+ * A PRTimeInterval value to be used for I/O waits for this socket. If
+ * zero, non-blocking I/O is to be used.
+ * "netAddr"
+ * The PRNetAddr to be used for the Bind function, if this is a server
+ * socket, or for the Connect, if this is a client socket.
+ * "pSocket"
+ * The address at which the Socket is to be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Socket Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Socket_Create(
+ PKIX_Boolean isServer,
+ PRIntervalTime timeout,
+ PRNetAddr *netAddr,
+ PRErrorCode *status,
+ PKIX_PL_Socket **pSocket,
+ void *plContext)
+{
+ PKIX_PL_Socket *socket = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_Create");
+ PKIX_NULLCHECK_ONE(pSocket);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_SOCKET_TYPE,
+ sizeof (PKIX_PL_Socket),
+ (PKIX_PL_Object **)&socket,
+ plContext),
+ PKIX_COULDNOTCREATESOCKETOBJECT);
+
+ socket->isServer = isServer;
+ socket->timeout = timeout;
+ socket->clientSock = NULL;
+ socket->serverSock = NULL;
+ socket->netAddr = netAddr;
+
+ socket->callbackList.listenCallback = pkix_pl_Socket_Listen;
+ socket->callbackList.acceptCallback = pkix_pl_Socket_Accept;
+ socket->callbackList.connectcontinueCallback =
+ pkix_pl_Socket_ConnectContinue;
+ socket->callbackList.sendCallback = pkix_pl_Socket_Send;
+ socket->callbackList.recvCallback = pkix_pl_Socket_Recv;
+ socket->callbackList.pollCallback = pkix_pl_Socket_Poll;
+ socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown;
+
+ if (isServer) {
+ PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext),
+ PKIX_SOCKETCREATESERVERFAILED);
+ *status = 0;
+ } else {
+ socket->timeout = timeout;
+ PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext),
+ PKIX_SOCKETCREATECLIENTFAILED);
+ PKIX_CHECK(pkix_pl_Socket_Connect(socket, status, plContext),
+ PKIX_SOCKETCONNECTFAILED);
+ }
+
+ *pSocket = socket;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(socket);
+ }
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_CreateByName
+ * DESCRIPTION:
+ *
+ * This function creates a new Socket, setting it to be a server or a client
+ * according to the value of "isServer", setting its timeout value from
+ * "timeout" and server address and port number from "serverName", and stores
+ * the status at "pStatus" and the created Socket at "pSocket".
+ *
+ * If isServer is PKIX_TRUE, it is attempted to create the socket with an ip
+ * address of PR_INADDR_ANY.
+ *
+ * PARAMETERS:
+ * "isServer"
+ * The Boolean value indicating if PKIX_TRUE, that a server socket (using
+ * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a
+ * client socket (using Connect) is to be created.
+ * "timeout"
+ * A PRTimeInterval value to be used for I/O waits for this socket. If
+ * zero, non-blocking I/O is to be used.
+ * "serverName"
+ * Address of a character string consisting of the server's domain name
+ * followed by a colon and a port number for the desired socket.
+ * "pStatus"
+ * Address at which the PRErrorCode resulting from the create is
+ * stored. Must be non-NULL.
+ * "pSocket"
+ * The address at which the Socket is to be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Socket Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Socket_CreateByName(
+ PKIX_Boolean isServer,
+ PRIntervalTime timeout,
+ char *serverName,
+ PRErrorCode *pStatus,
+ PKIX_PL_Socket **pSocket,
+ void *plContext)
+{
+ PRNetAddr netAddr;
+ PKIX_PL_Socket *socket = NULL;
+ char *sepPtr = NULL;
+ PRHostEnt hostent;
+ PRIntn hostenum;
+ PRStatus prstatus = PR_FAILURE;
+ char buf[PR_NETDB_BUF_SIZE];
+ PRUint16 portNum = 0;
+ char *localCopyName = NULL;
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateByName");
+ PKIX_NULLCHECK_TWO(serverName, pSocket);
+
+ localCopyName = PL_strdup(serverName);
+
+ sepPtr = strchr(localCopyName, ':');
+ /* First strip off the portnum, if present, from the end of the name */
+ if (sepPtr) {
+ *sepPtr++ = '\0';
+ portNum = (PRUint16)atoi(sepPtr);
+ } else {
+ portNum = (PRUint16)LDAP_PORT;
+ }
+
+ prstatus = PR_GetHostByName(localCopyName, buf, sizeof(buf), &hostent);
+
+ if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) {
+ /*
+ * The hostname may be a fully-qualified name. Try using just
+ * the leftmost component in our lookup.
+ */
+ sepPtr = strchr(localCopyName, '.');
+ if (sepPtr) {
+ *sepPtr++ = '\0';
+ }
+ prstatus = PR_GetHostByName
+ (localCopyName, buf, sizeof(buf), &hostent);
+
+ if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) {
+ PKIX_ERROR
+ (PKIX_PRGETHOSTBYNAMEREJECTSHOSTNAMEARGUMENT);
+ }
+ }
+
+ netAddr.inet.family = PR_AF_INET;
+ netAddr.inet.port = PR_htons(portNum);
+
+ if (isServer) {
+
+ netAddr.inet.ip = PR_INADDR_ANY;
+
+ } else {
+
+ hostenum = PR_EnumerateHostEnt(0, &hostent, portNum, &netAddr);
+ if (hostenum == -1) {
+ PKIX_ERROR(PKIX_PRENUMERATEHOSTENTFAILED);
+ }
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_SOCKET_TYPE,
+ sizeof (PKIX_PL_Socket),
+ (PKIX_PL_Object **)&socket,
+ plContext),
+ PKIX_COULDNOTCREATESOCKETOBJECT);
+
+ socket->isServer = isServer;
+ socket->timeout = timeout;
+ socket->clientSock = NULL;
+ socket->serverSock = NULL;
+ socket->netAddr = &netAddr;
+
+ socket->callbackList.listenCallback = pkix_pl_Socket_Listen;
+ socket->callbackList.acceptCallback = pkix_pl_Socket_Accept;
+ socket->callbackList.connectcontinueCallback =
+ pkix_pl_Socket_ConnectContinue;
+ socket->callbackList.sendCallback = pkix_pl_Socket_Send;
+ socket->callbackList.recvCallback = pkix_pl_Socket_Recv;
+ socket->callbackList.pollCallback = pkix_pl_Socket_Poll;
+ socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown;
+
+ if (isServer) {
+ PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext),
+ PKIX_SOCKETCREATESERVERFAILED);
+ *pStatus = 0;
+ } else {
+ PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext),
+ PKIX_SOCKETCREATECLIENTFAILED);
+ PKIX_CHECK(pkix_pl_Socket_Connect(socket, pStatus, plContext),
+ PKIX_SOCKETCONNECTFAILED);
+ }
+
+ *pSocket = socket;
+
+cleanup:
+ PL_strfree(localCopyName);
+
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(socket);
+ }
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_CreateByHostAndPort
+ * DESCRIPTION:
+ *
+ * This function creates a new Socket, setting it to be a server or a client
+ * according to the value of "isServer", setting its timeout value from
+ * "timeout", host from "hostname", and port number from "portNum", and stores
+ * the status at "pStatus" and the created Socket at "pSocket".
+ *
+ * If isServer is PKIX_TRUE, it is attempted to create the socket with an ip
+ * address of PR_INADDR_ANY.
+ *
+ * PARAMETERS:
+ * "isServer"
+ * The Boolean value indicating if PKIX_TRUE, that a server socket (using
+ * Bind, Listen, and Accept) is to be created, or if PKIX_FALSE, that a
+ * client socket (using Connect) is to be created.
+ * "timeout"
+ * A PRTimeInterval value to be used for I/O waits for this socket. If
+ * zero, non-blocking I/O is to be used.
+ * "hostname"
+ * Address of a character string consisting of the server's domain name.
+ * "portNum"
+ * UInt16 value of the port number for the desired socket.
+ * "pStatus"
+ * Address at which the PRErrorCode resulting from the create is
+ * stored. Must be non-NULL.
+ * "pSocket"
+ * The address at which the Socket is to be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Socket Error if the function fails in
+ * a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Socket_CreateByHostAndPort(
+ PKIX_Boolean isServer,
+ PRIntervalTime timeout,
+ char *hostname,
+ PRUint16 portnum,
+ PRErrorCode *pStatus,
+ PKIX_PL_Socket **pSocket,
+ void *plContext)
+{
+ PRNetAddr netAddr;
+ PKIX_PL_Socket *socket = NULL;
+ char *sepPtr = NULL;
+ PRHostEnt hostent;
+ PRIntn hostenum;
+ PRStatus prstatus = PR_FAILURE;
+ char buf[PR_NETDB_BUF_SIZE];
+
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_CreateByHostAndPort");
+ PKIX_NULLCHECK_THREE(hostname, pStatus, pSocket);
+
+
+ prstatus = PR_GetHostByName(hostname, buf, sizeof(buf), &hostent);
+
+ if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) {
+ /*
+ * The hostname may be a fully-qualified name. Try using just
+ * the leftmost component in our lookup.
+ */
+ sepPtr = strchr(hostname, '.');
+ if (sepPtr) {
+ *sepPtr++ = '\0';
+ }
+ prstatus = PR_GetHostByName(hostname, buf, sizeof(buf), &hostent);
+
+ if ((prstatus != PR_SUCCESS) || (hostent.h_length != 4)) {
+ PKIX_ERROR
+ (PKIX_PRGETHOSTBYNAMEREJECTSHOSTNAMEARGUMENT);
+ }
+ }
+
+ netAddr.inet.family = PR_AF_INET;
+ netAddr.inet.port = PR_htons(portnum);
+
+ if (isServer) {
+
+ netAddr.inet.ip = PR_INADDR_ANY;
+
+ } else {
+
+ hostenum = PR_EnumerateHostEnt(0, &hostent, portnum, &netAddr);
+ if (hostenum == -1) {
+ PKIX_ERROR(PKIX_PRENUMERATEHOSTENTFAILED);
+ }
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_SOCKET_TYPE,
+ sizeof (PKIX_PL_Socket),
+ (PKIX_PL_Object **)&socket,
+ plContext),
+ PKIX_COULDNOTCREATESOCKETOBJECT);
+
+ socket->isServer = isServer;
+ socket->timeout = timeout;
+ socket->clientSock = NULL;
+ socket->serverSock = NULL;
+ socket->netAddr = &netAddr;
+
+ socket->callbackList.listenCallback = pkix_pl_Socket_Listen;
+ socket->callbackList.acceptCallback = pkix_pl_Socket_Accept;
+ socket->callbackList.connectcontinueCallback =
+ pkix_pl_Socket_ConnectContinue;
+ socket->callbackList.sendCallback = pkix_pl_Socket_Send;
+ socket->callbackList.recvCallback = pkix_pl_Socket_Recv;
+ socket->callbackList.pollCallback = pkix_pl_Socket_Poll;
+ socket->callbackList.shutdownCallback = pkix_pl_Socket_Shutdown;
+
+ if (isServer) {
+ PKIX_CHECK(pkix_pl_Socket_CreateServer(socket, plContext),
+ PKIX_SOCKETCREATESERVERFAILED);
+ *pStatus = 0;
+ } else {
+ PKIX_CHECK(pkix_pl_Socket_CreateClient(socket, plContext),
+ PKIX_SOCKETCREATECLIENTFAILED);
+ PKIX_CHECK(pkix_pl_Socket_Connect(socket, pStatus, plContext),
+ PKIX_SOCKETCONNECTFAILED);
+ }
+
+ *pSocket = socket;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED) {
+ PKIX_DECREF(socket);
+ }
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_GetCallbackList
+ */
+PKIX_Error *
+pkix_pl_Socket_GetCallbackList(
+ PKIX_PL_Socket *socket,
+ PKIX_PL_Socket_Callback **pCallbackList,
+ void *plContext)
+{
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_GetCallbackList");
+ PKIX_NULLCHECK_TWO(socket, pCallbackList);
+
+ *pCallbackList = &(socket->callbackList);
+
+ PKIX_RETURN(SOCKET);
+}
+
+/*
+ * FUNCTION: pkix_pl_Socket_GetPRFileDesc
+ */
+PKIX_Error *
+pkix_pl_Socket_GetPRFileDesc(
+ PKIX_PL_Socket *socket,
+ PRFileDesc **pDesc,
+ void *plContext)
+{
+ PKIX_ENTER(SOCKET, "pkix_pl_Socket_GetPRFileDesc");
+ PKIX_NULLCHECK_TWO(socket, pDesc);
+
+ *pDesc = socket->clientSock;
+
+ PKIX_RETURN(SOCKET);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.h b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.h
new file mode 100644
index 000000000..abf6628b3
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/module/pkix_pl_socket.h
@@ -0,0 +1,209 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_socket.h
+ *
+ * Socket Object Type Definition
+ *
+ */
+
+#ifndef _PKIX_PL_SOCKET_H
+#define _PKIX_PL_SOCKET_H
+
+#include <errno.h>
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {
+ SOCKET_BOUND,
+ SOCKET_LISTENING,
+ SOCKET_ACCEPTPENDING,
+ SOCKET_UNCONNECTED,
+ SOCKET_CONNECTPENDING,
+ SOCKET_CONNECTED,
+ SOCKET_SENDPENDING,
+ SOCKET_RCVPENDING,
+ SOCKET_SENDRCVPENDING,
+ SOCKET_SHUTDOWN
+} SockStatus;
+
+/* This is the default port number, if none is supplied to CreateByName. */
+#define LDAP_PORT 389
+
+/*
+ * These callbacks allow a user to substitute a counterfeit socket in places
+ * where a PKIX_PL_Socket is expected. A conforming usage will use the
+ * ListenCallback function instead of Listen, AcceptCallback instead of Accept,
+ * etc. The counterfeit socket may have special capabilites such as the
+ * ability to do proxy authentication, etc.
+ */
+
+typedef PKIX_Error *
+(*pkix_pl_Socket_ListenCallback)(
+ PKIX_PL_Socket *socket,
+ PKIX_UInt32 backlog,
+ void *plContext);
+
+typedef PKIX_Error *
+(*pkix_pl_Socket_AcceptCallback)(
+ PKIX_PL_Socket *socket,
+ PKIX_PL_Socket **pRendezvousSock,
+ void *plContext);
+
+typedef PKIX_Error *
+(*pkix_pl_Socket_ConnectContinueCallback)(
+ PKIX_PL_Socket *socket,
+ PRErrorCode *pStatus,
+ void *plContext);
+
+typedef PKIX_Error *
+(*pkix_pl_Socket_SendCallback)(
+ PKIX_PL_Socket *sendSock,
+ void *buf,
+ PKIX_UInt32 bytesToWrite,
+ PKIX_Int32 *pBytesWritten,
+ void *plContext);
+
+typedef PKIX_Error *
+(*pkix_pl_Socket_RecvCallback)(
+ PKIX_PL_Socket *rcvSock,
+ void *buf,
+ PKIX_UInt32 capacity,
+ PKIX_Int32 *pBytesRead,
+ void *plContext);
+
+typedef PKIX_Error *
+(*pkix_pl_Socket_PollCallback)(
+ PKIX_PL_Socket *sock,
+ PKIX_Int32 *pBytesWritten,
+ PKIX_Int32 *pBytesRead,
+ void *plContext);
+
+typedef PKIX_Error *
+(*pkix_pl_Socket_ShutdownCallback)(
+ PKIX_PL_Socket *socket, void *plContext);
+
+typedef struct PKIX_PL_Socket_CallbackStruct {
+ pkix_pl_Socket_ListenCallback listenCallback;
+ pkix_pl_Socket_AcceptCallback acceptCallback;
+ pkix_pl_Socket_ConnectContinueCallback connectcontinueCallback;
+ pkix_pl_Socket_SendCallback sendCallback;
+ pkix_pl_Socket_RecvCallback recvCallback;
+ pkix_pl_Socket_PollCallback pollCallback;
+ pkix_pl_Socket_ShutdownCallback shutdownCallback;
+} PKIX_PL_Socket_Callback;
+
+struct PKIX_PL_SocketStruct {
+ PKIX_Boolean isServer;
+ PRIntervalTime timeout; /* zero for non-blocking I/O */
+ SockStatus status;
+ PRFileDesc *clientSock;
+ PRFileDesc *serverSock;
+ void *readBuf;
+ void *writeBuf;
+ PKIX_UInt32 readBufSize;
+ PKIX_UInt32 writeBufSize;
+ PRNetAddr *netAddr;
+ PKIX_PL_Socket_Callback callbackList;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_Socket_RegisterSelf(void *plContext);
+
+PKIX_Error *
+pkix_pl_Socket_Create(
+ PKIX_Boolean isServer,
+ PRIntervalTime timeout, /* zero for non-blocking I/O */
+ PRNetAddr *netAddr,
+ PRErrorCode *status,
+ PKIX_PL_Socket **pSocket,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_Socket_CreateByName(
+ PKIX_Boolean isServer,
+ PRIntervalTime timeout,
+ char *serverName,
+ PRErrorCode *pStatus,
+ PKIX_PL_Socket **pSocket,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_Socket_CreateByHostAndPort(
+ PKIX_Boolean isServer,
+ PRIntervalTime timeout,
+ char *hostname,
+ PRUint16 portnum,
+ PRErrorCode *pStatus,
+ PKIX_PL_Socket **pSocket,
+ void *plContext);
+
+/* Do not use these functions directly; use their callback variants instead
+ * static PKIX_Error *
+ * pkix_pl_Socket_Listen(
+ * PKIX_PL_Socket *socket,
+ * PKIX_UInt32 backlog,
+ * void *plContext);
+ *
+ * static PKIX_Error *
+ * pkix_pl_Socket_Accept(
+ * PKIX_PL_Socket *socket,
+ * PKIX_PL_Socket **pRendezvousSock,
+ * void *plContext);
+ *
+ * static PKIX_Error *
+ * pkix_pl_Socket_ConnectContinue(
+ * PKIX_PL_Socket *socket,
+ * PRErrorCode *pStatus,
+ * void *plContext);
+ *
+ * static PKIX_Error *
+ * pkix_pl_Socket_Send(
+ * PKIX_PL_Socket *sendSock,
+ * void *buf,
+ * PKIX_UInt32 bytesToWrite,
+ * PKIX_Int32 *pBytesWritten,
+ * void *plContext);
+ *
+ * static PKIX_Error *
+ * pkix_pl_Socket_Recv(
+ * PKIX_PL_Socket *rcvSock,
+ * void *buf,
+ * PKIX_UInt32 capacity,
+ * PKIX_Int32 *pBytesRead,
+ * void *plContext);
+ *
+ * static PKIX_Error *
+ * pkix_pl_Socket_Poll(
+ * PKIX_PL_Socket *sock,
+ * PKIX_Int32 *pBytesWritten,
+ * PKIX_Int32 *pBytesRead,
+ * void *plContext);
+ *
+ * static PKIX_Error *
+ * pkix_pl_Socket_Shutdown(
+ * PKIX_PL_Socket *socket, void *plContext);
+ */
+
+PKIX_Error *
+pkix_pl_Socket_GetCallbackList(
+ PKIX_PL_Socket *socket,
+ PKIX_PL_Socket_Callback **pCallbackList,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_Socket_GetPRFileDesc(
+ PKIX_PL_Socket *socket,
+ PRFileDesc **pDesc,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_SOCKET_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/Makefile b/security/nss/lib/libpkix/pkix_pl_nss/pki/Makefile
new file mode 100755
index 000000000..0fb6c9058
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/Makefile
@@ -0,0 +1,49 @@
+#! gmake
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#######################################################################
+# (1) Include initial platform-independent assignments (MANDATORY). #
+#######################################################################
+
+include manifest.mn
+
+#######################################################################
+# (2) Include "global" configuration information. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/config.mk
+
+#######################################################################
+# (3) Include "component" configuration information. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (4) Include "local" platform-dependent assignments (OPTIONAL). #
+#######################################################################
+
+include config.mk
+
+#######################################################################
+# (5) Execute "global" rules. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/rules.mk
+
+#######################################################################
+# (6) Execute "component" rules. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (7) Execute "local" rules. (OPTIONAL). #
+#######################################################################
+
+export:: private_export
+
+
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/config.mk b/security/nss/lib/libpkix/pkix_pl_nss/pki/config.mk
new file mode 100755
index 000000000..b8c03de79
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/config.mk
@@ -0,0 +1,15 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#
+# Override TARGETS variable so that only static libraries
+# are specifed as dependencies within rules.mk.
+#
+
+TARGETS = $(LIBRARY)
+SHARED_LIBRARY =
+IMPORT_LIBRARY =
+PROGRAM =
+
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/exports.gyp b/security/nss/lib/libpkix/pkix_pl_nss/pki/exports.gyp
new file mode 100644
index 000000000..616f94fd4
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/exports.gyp
@@ -0,0 +1,41 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+{
+ 'includes': [
+ '../../../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'lib_libpkix_pkix_pl_nss_pki_exports',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'files': [
+ 'pkix_pl_basicconstraints.h',
+ 'pkix_pl_cert.h',
+ 'pkix_pl_certpolicyinfo.h',
+ 'pkix_pl_certpolicymap.h',
+ 'pkix_pl_certpolicyqualifier.h',
+ 'pkix_pl_crl.h',
+ 'pkix_pl_crldp.h',
+ 'pkix_pl_crlentry.h',
+ 'pkix_pl_date.h',
+ 'pkix_pl_generalname.h',
+ 'pkix_pl_infoaccess.h',
+ 'pkix_pl_nameconstraints.h',
+ 'pkix_pl_ocspcertid.h',
+ 'pkix_pl_ocsprequest.h',
+ 'pkix_pl_ocspresponse.h',
+ 'pkix_pl_publickey.h',
+ 'pkix_pl_x500name.h'
+ ],
+ 'destination': '<(nss_private_dist_dir)/<(module)'
+ }
+ ]
+ }
+ ],
+ 'variables': {
+ 'module': 'nss'
+ }
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/manifest.mn b/security/nss/lib/libpkix/pkix_pl_nss/pki/manifest.mn
new file mode 100755
index 000000000..f8d4571e1
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/manifest.mn
@@ -0,0 +1,53 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+CORE_DEPTH = ../../../..
+
+EXPORTS = \
+ $(NULL)
+
+PRIVATE_EXPORTS = \
+ pkix_pl_basicconstraints.h \
+ pkix_pl_cert.h \
+ pkix_pl_certpolicyinfo.h \
+ pkix_pl_certpolicymap.h \
+ pkix_pl_certpolicyqualifier.h \
+ pkix_pl_crl.h \
+ pkix_pl_crldp.h \
+ pkix_pl_crlentry.h \
+ pkix_pl_date.h \
+ pkix_pl_generalname.h \
+ pkix_pl_infoaccess.h \
+ pkix_pl_nameconstraints.h \
+ pkix_pl_ocsprequest.h \
+ pkix_pl_ocspresponse.h \
+ pkix_pl_publickey.h \
+ pkix_pl_x500name.h \
+ pkix_pl_ocspcertid.h \
+ $(NULL)
+
+MODULE = nss
+
+CSRCS = \
+ pkix_pl_basicconstraints.c \
+ pkix_pl_cert.c \
+ pkix_pl_certpolicyinfo.c \
+ pkix_pl_certpolicymap.c \
+ pkix_pl_certpolicyqualifier.c \
+ pkix_pl_crl.c \
+ pkix_pl_crldp.c \
+ pkix_pl_crlentry.c \
+ pkix_pl_date.c \
+ pkix_pl_generalname.c \
+ pkix_pl_infoaccess.c \
+ pkix_pl_nameconstraints.c \
+ pkix_pl_ocsprequest.c \
+ pkix_pl_ocspresponse.c \
+ pkix_pl_publickey.c \
+ pkix_pl_x500name.c \
+ pkix_pl_ocspcertid.c \
+ $(NULL)
+
+LIBRARY_NAME = pkixpki
+
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pki.gyp b/security/nss/lib/libpkix/pkix_pl_nss/pki/pki.gyp
new file mode 100644
index 000000000..af7730c0b
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pki.gyp
@@ -0,0 +1,39 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+{
+ 'includes': [
+ '../../../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'pkixpki',
+ 'type': 'static_library',
+ 'sources': [
+ 'pkix_pl_basicconstraints.c',
+ 'pkix_pl_cert.c',
+ 'pkix_pl_certpolicyinfo.c',
+ 'pkix_pl_certpolicymap.c',
+ 'pkix_pl_certpolicyqualifier.c',
+ 'pkix_pl_crl.c',
+ 'pkix_pl_crldp.c',
+ 'pkix_pl_crlentry.c',
+ 'pkix_pl_date.c',
+ 'pkix_pl_generalname.c',
+ 'pkix_pl_infoaccess.c',
+ 'pkix_pl_nameconstraints.c',
+ 'pkix_pl_ocspcertid.c',
+ 'pkix_pl_ocsprequest.c',
+ 'pkix_pl_ocspresponse.c',
+ 'pkix_pl_publickey.c',
+ 'pkix_pl_x500name.c'
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports'
+ ]
+ }
+ ],
+ 'variables': {
+ 'module': 'nss'
+ }
+} \ No newline at end of file
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.c
new file mode 100644
index 000000000..81615da37
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.c
@@ -0,0 +1,407 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_basicconstraints.c
+ *
+ * BasicConstraints Object Functions
+ *
+ */
+
+#include "pkix_pl_basicconstraints.h"
+
+/*
+ * FUNCTION: pkix_pl_CertBasicConstraints_Create
+ * DESCRIPTION:
+ *
+ * Creates a new CertBasicConstraints object whose CA Flag has the value
+ * given by the Boolean value of "isCA" and whose path length field has the
+ * value given by the "pathLen" argument and stores it at "pObject".
+ *
+ * PARAMETERS
+ * "isCA"
+ * Boolean value with the desired value of CA Flag.
+ * "pathLen"
+ * a PKIX_Int32 with the desired value of path length
+ * "pObject"
+ * Address of object pointer's destination. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertBasicConstraints Error if the function fails
+ * in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_CertBasicConstraints_Create(
+ PKIX_Boolean isCA,
+ PKIX_Int32 pathLen,
+ PKIX_PL_CertBasicConstraints **pObject,
+ void *plContext)
+{
+ PKIX_PL_CertBasicConstraints *basic = NULL;
+
+ PKIX_ENTER(CERTBASICCONSTRAINTS,
+ "pkix_pl_CertBasicConstraints_Create");
+ PKIX_NULLCHECK_ONE(pObject);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_CERTBASICCONSTRAINTS_TYPE,
+ sizeof (PKIX_PL_CertBasicConstraints),
+ (PKIX_PL_Object **)&basic,
+ plContext),
+ PKIX_COULDNOTCREATECERTBASICCONSTRAINTSOBJECT);
+
+ basic->isCA = isCA;
+
+ /* pathLen has meaning only for CAs, but it's not worth checking */
+ basic->pathLen = pathLen;
+
+ *pObject = basic;
+
+cleanup:
+
+ PKIX_RETURN(CERTBASICCONSTRAINTS);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertBasicConstraints_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertBasicConstraints_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_CertBasicConstraints *certB = NULL;
+
+ PKIX_ENTER(CERTBASICCONSTRAINTS,
+ "pkix_pl_CertBasicConstraints_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_CERTBASICCONSTRAINTS_TYPE, plContext),
+ PKIX_OBJECTNOTCERTBASICCONSTRAINTS);
+
+ certB = (PKIX_PL_CertBasicConstraints*)object;
+
+ certB->isCA = PKIX_FALSE;
+ certB->pathLen = 0;
+
+cleanup:
+
+ PKIX_RETURN(CERTBASICCONSTRAINTS);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertBasicConstraints_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertBasicConstraints_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_String *certBasicConstraintsString = NULL;
+ PKIX_PL_CertBasicConstraints *certB = NULL;
+ PKIX_Boolean isCA = PKIX_FALSE;
+ PKIX_Int32 pathLen = 0;
+ PKIX_PL_String *outString = NULL;
+ char *fmtString = NULL;
+ PKIX_Boolean pathlenArg = PKIX_FALSE;
+
+ PKIX_ENTER(CERTBASICCONSTRAINTS,
+ "pkix_pl_CertBasicConstraints_toString");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_CERTBASICCONSTRAINTS_TYPE, plContext),
+ PKIX_FIRSTARGUMENTNOTCERTBASICCONSTRAINTSOBJECT);
+
+ certB = (PKIX_PL_CertBasicConstraints *)object;
+
+ /*
+ * if CA == TRUE
+ * if pathLen == CERT_UNLIMITED_PATH_CONSTRAINT
+ * print "CA(-1)"
+ * else print "CA(nnn)"
+ * if CA == FALSE, print "~CA"
+ */
+
+ isCA = certB->isCA;
+
+ if (isCA) {
+ pathLen = certB->pathLen;
+
+ if (pathLen == CERT_UNLIMITED_PATH_CONSTRAINT) {
+ /* print "CA(-1)" */
+ fmtString = "CA(-1)";
+ pathlenArg = PKIX_FALSE;
+ } else {
+ /* print "CA(pathLen)" */
+ fmtString = "CA(%d)";
+ pathlenArg = PKIX_TRUE;
+ }
+ } else {
+ /* print "~CA" */
+ fmtString = "~CA";
+ pathlenArg = PKIX_FALSE;
+ }
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII,
+ fmtString,
+ 0,
+ &certBasicConstraintsString,
+ plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ if (pathlenArg) {
+ PKIX_CHECK(PKIX_PL_Sprintf
+ (&outString,
+ plContext,
+ certBasicConstraintsString,
+ pathLen),
+ PKIX_SPRINTFFAILED);
+ } else {
+ PKIX_CHECK(PKIX_PL_Sprintf
+ (&outString,
+ plContext,
+ certBasicConstraintsString),
+ PKIX_SPRINTFFAILED);
+ }
+
+ *pString = outString;
+
+cleanup:
+
+ PKIX_DECREF(certBasicConstraintsString);
+
+ PKIX_RETURN(CERTBASICCONSTRAINTS);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertBasicConstraints_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertBasicConstraints_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_CertBasicConstraints *certB = NULL;
+ PKIX_Boolean isCA = PKIX_FALSE;
+ PKIX_Int32 pathLen = 0;
+ PKIX_Int32 hashInput = 0;
+ PKIX_UInt32 cbcHash = 0;
+
+ PKIX_ENTER(CERTBASICCONSTRAINTS,
+ "pkix_pl_CertBasicConstraints_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_CERTBASICCONSTRAINTS_TYPE, plContext),
+ PKIX_OBJECTNOTCERTBASICCONSTRAINTS);
+
+ certB = (PKIX_PL_CertBasicConstraints *)object;
+
+ /*
+ * if CA == TRUE
+ * hash(pathLen + 1 - PKIX_UNLIMITED_PATH_CONSTRAINT)
+ * if CA == FALSE, hash(0)
+ */
+
+ isCA = certB->isCA;
+
+ if (isCA) {
+ pathLen = certB->pathLen;
+
+ hashInput = pathLen + 1 - PKIX_UNLIMITED_PATH_CONSTRAINT;
+ }
+
+ PKIX_CHECK(pkix_hash
+ ((const unsigned char *)&hashInput,
+ sizeof (hashInput),
+ &cbcHash,
+ plContext),
+ PKIX_HASHFAILED);
+
+ *pHashcode = cbcHash;
+
+cleanup:
+
+ PKIX_RETURN(CERTBASICCONSTRAINTS);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_CertBasicConstraints_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertBasicConstraints_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_PL_CertBasicConstraints *firstCBC = NULL;
+ PKIX_PL_CertBasicConstraints *secondCBC = NULL;
+ PKIX_UInt32 secondType;
+ PKIX_Boolean firstIsCA = PKIX_FALSE;
+ PKIX_Boolean secondIsCA = PKIX_FALSE;
+ PKIX_Int32 firstPathLen = 0;
+ PKIX_Int32 secondPathLen = 0;
+
+ PKIX_ENTER(CERTBASICCONSTRAINTS,
+ "pkix_pl_CertBasicConstraints_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ /* test that firstObject is a CertBasicConstraints */
+ PKIX_CHECK(pkix_CheckType
+ (firstObject, PKIX_CERTBASICCONSTRAINTS_TYPE, plContext),
+ PKIX_FIRSTOBJECTNOTCERTBASICCONSTRAINTS);
+
+ /*
+ * Since we know firstObject is a CertBasicConstraints,
+ * if both references are identical, they must be equal
+ */
+ if (firstObject == secondObject){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondObject isn't a CertBasicConstraints, we
+ * don't throw an error. We simply return FALSE.
+ */
+ PKIX_CHECK(PKIX_PL_Object_GetType
+ (secondObject, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+ if (secondType != PKIX_CERTBASICCONSTRAINTS_TYPE) {
+ *pResult = PKIX_FALSE;
+ goto cleanup;
+ }
+
+ firstCBC = (PKIX_PL_CertBasicConstraints *)firstObject;
+ secondCBC = (PKIX_PL_CertBasicConstraints *)secondObject;
+
+ /*
+ * Compare the value of the CAFlag components
+ */
+
+ firstIsCA = firstCBC->isCA;
+
+ /*
+ * Failure here would be an error, not merely a miscompare,
+ * since we know second is a CertBasicConstraints.
+ */
+ secondIsCA = secondCBC->isCA;
+
+ /*
+ * If isCA flags differ, the objects are not equal.
+ */
+ if (secondIsCA != firstIsCA) {
+ *pResult = PKIX_FALSE;
+ goto cleanup;
+ }
+
+ /*
+ * If isCA was FALSE, the objects are equal, because
+ * pathLen is meaningless in that case.
+ */
+ if (!firstIsCA) {
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ firstPathLen = firstCBC->pathLen;
+ secondPathLen = secondCBC->pathLen;
+
+ *pResult = (secondPathLen == firstPathLen);
+
+cleanup:
+
+ PKIX_RETURN(CERTBASICCONSTRAINTS);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertBasicConstraints_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_CERTBASICCONSTRAINTS_TYPE and its related
+ * functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize,
+ * which should only be called once, it is acceptable that
+ * this function is not thread-safe.
+ */
+PKIX_Error *
+pkix_pl_CertBasicConstraints_RegisterSelf(void *plContext)
+{
+
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(CERTBASICCONSTRAINTS,
+ "pkix_pl_CertBasicConstraints_RegisterSelf");
+
+ entry.description = "CertBasicConstraints";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_CertBasicConstraints);
+ entry.destructor = pkix_pl_CertBasicConstraints_Destroy;
+ entry.equalsFunction = pkix_pl_CertBasicConstraints_Equals;
+ entry.hashcodeFunction = pkix_pl_CertBasicConstraints_Hashcode;
+ entry.toStringFunction = pkix_pl_CertBasicConstraints_ToString;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_CERTBASICCONSTRAINTS_TYPE] = entry;
+
+ PKIX_RETURN(CERTBASICCONSTRAINTS);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_BasicConstraints_GetCAFlag
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_BasicConstraints_GetCAFlag(
+ PKIX_PL_CertBasicConstraints *basicConstraints,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_ENTER(CERTBASICCONSTRAINTS,
+ "PKIX_PL_BasicConstraintsGetCAFlag");
+ PKIX_NULLCHECK_TWO(basicConstraints, pResult);
+
+ *pResult = basicConstraints->isCA;
+
+ PKIX_RETURN(CERTBASICCONSTRAINTS);
+}
+
+/*
+ * FUNCTION: PKIX_PL_BasicConstraints_GetPathLenConstraint
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_BasicConstraints_GetPathLenConstraint(
+ PKIX_PL_CertBasicConstraints *basicConstraints,
+ PKIX_Int32 *pPathLenConstraint,
+ void *plContext)
+{
+ PKIX_ENTER(CERTBASICCONSTRAINTS,
+ "PKIX_PL_BasicConstraintsGetPathLenConstraint");
+ PKIX_NULLCHECK_TWO(basicConstraints, pPathLenConstraint);
+
+ *pPathLenConstraint = basicConstraints->pathLen;
+
+ PKIX_RETURN(CERTBASICCONSTRAINTS);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.h
new file mode 100644
index 000000000..857529c95
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_basicconstraints.h
@@ -0,0 +1,47 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_basicconstraints.h
+ *
+ * BasicConstraints Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_BASICCONSTRAINTS_H
+#define _PKIX_PL_BASICCONSTRAINTS_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* This structure reflects the contents of the basic constraints
+ * extension as described in Section 4.2.1.10 of RFC 3280.
+ * The cA flag indicates whether the public key in this certificate
+ * belongs to a certification authority. The pathLen constraint
+ * gives the maximum number of non-self-issued intermediate certificates
+ * that may follow this certificate in a valid certification path.
+ */
+struct PKIX_PL_CertBasicConstraintsStruct {
+ PKIX_Boolean isCA;
+ PKIX_Int32 pathLen;
+};
+
+PKIX_Error *
+pkix_pl_CertBasicConstraints_Create(
+ PKIX_Boolean isCA,
+ PKIX_Int32 pathLen,
+ PKIX_PL_CertBasicConstraints **object,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_CertBasicConstraints_RegisterSelf(
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_BASICCONSTRAINTS_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c
new file mode 100644
index 000000000..fa8f1851e
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.c
@@ -0,0 +1,3714 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_cert.c
+ *
+ * Certificate Object Functions
+ *
+ */
+
+#include "pkix_pl_cert.h"
+
+extern PKIX_PL_HashTable *cachedCertSigTable;
+
+/* --Private-Cert-Functions------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_Cert_IsExtensionCritical
+ * DESCRIPTION:
+ *
+ * Checks the Cert specified by "cert" to determine whether the extension
+ * whose tag is the UInt32 value given by "tag" is marked as a critical
+ * extension, and stores the result in "pCritical".
+ *
+ * Tags are the index into the table "oids" of SECOidData defined in the
+ * file secoid.c. Constants, such as SEC_OID_X509_CERTIFICATE_POLICIES, are
+ * are defined in secoidt.h for most of the table entries.
+ *
+ * If the specified tag is invalid (not in the list of tags) or if the
+ * extension is not found in the certificate, PKIX_FALSE is stored.
+ *
+ * PARAMETERS
+ * "cert"
+ * Address of Cert whose extensions are to be examined. Must be non-NULL.
+ * "tag"
+ * The UInt32 value of the tag for the extension whose criticality is
+ * to be determined
+ * "pCritical"
+ * Address where the Boolean value will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Cert_IsExtensionCritical(
+ PKIX_PL_Cert *cert,
+ PKIX_UInt32 tag,
+ PKIX_Boolean *pCritical,
+ void *plContext)
+{
+ PKIX_Boolean criticality = PKIX_FALSE;
+ CERTCertExtension **extensions = NULL;
+ SECStatus rv;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_IsExtensionCritical");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pCritical);
+
+ extensions = cert->nssCert->extensions;
+ PKIX_NULLCHECK_ONE(extensions);
+
+ PKIX_CERT_DEBUG("\t\tCalling CERT_GetExtenCriticality).\n");
+ rv = CERT_GetExtenCriticality(extensions, tag, &criticality);
+ if (SECSuccess == rv) {
+ *pCritical = criticality;
+ } else {
+ *pCritical = PKIX_FALSE;
+ }
+
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_DecodePolicyInfo
+ * DESCRIPTION:
+ *
+ * Decodes the contents of the CertificatePolicy extension in the
+ * CERTCertificate pointed to by "nssCert", to create a List of
+ * CertPolicyInfos, which is stored at the address "pCertPolicyInfos".
+ * A CERTCertificate contains the DER representation of the Cert.
+ * If this certificate does not have a CertificatePolicy extension,
+ * NULL will be stored. If a List is returned, it will be immutable.
+ *
+ * PARAMETERS
+ * "nssCert"
+ * Address of the Cert data whose extension is to be examined. Must be
+ * non-NULL.
+ * "pCertPolicyInfos"
+ * Address where the List of CertPolicyInfos will be stored. Must be
+ * non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Cert_DecodePolicyInfo(
+ CERTCertificate *nssCert,
+ PKIX_List **pCertPolicyInfos,
+ void *plContext)
+{
+
+ SECStatus rv;
+ SECItem encodedCertPolicyInfo;
+
+ /* Allocated in the arena; freed in CERT_Destroy... */
+ CERTCertificatePolicies *certPol = NULL;
+ CERTPolicyInfo **policyInfos = NULL;
+
+ /* Holder for the return value */
+ PKIX_List *infos = NULL;
+
+ PKIX_PL_OID *pkixOID = NULL;
+ PKIX_List *qualifiers = NULL;
+ PKIX_PL_CertPolicyInfo *certPolicyInfo = NULL;
+ PKIX_PL_CertPolicyQualifier *certPolicyQualifier = NULL;
+ PKIX_PL_ByteArray *qualifierArray = NULL;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_DecodePolicyInfo");
+ PKIX_NULLCHECK_TWO(nssCert, pCertPolicyInfos);
+
+ /* get PolicyInfo as a SECItem */
+ PKIX_CERT_DEBUG("\t\tCERT_FindCertExtension).\n");
+ rv = CERT_FindCertExtension
+ (nssCert,
+ SEC_OID_X509_CERTIFICATE_POLICIES,
+ &encodedCertPolicyInfo);
+ if (SECSuccess != rv) {
+ *pCertPolicyInfos = NULL;
+ goto cleanup;
+ }
+
+ /* translate PolicyInfo to CERTCertificatePolicies */
+ PKIX_CERT_DEBUG("\t\tCERT_DecodeCertificatePoliciesExtension).\n");
+ certPol = CERT_DecodeCertificatePoliciesExtension
+ (&encodedCertPolicyInfo);
+
+ PORT_Free(encodedCertPolicyInfo.data);
+
+ if (NULL == certPol) {
+ PKIX_ERROR(PKIX_CERTDECODECERTIFICATEPOLICIESEXTENSIONFAILED);
+ }
+
+ /*
+ * Check whether there are any policyInfos, so we can
+ * avoid creating an unnecessary List
+ */
+ policyInfos = certPol->policyInfos;
+ if (!policyInfos) {
+ *pCertPolicyInfos = NULL;
+ goto cleanup;
+ }
+
+ /* create a List of CertPolicyInfo Objects */
+ PKIX_CHECK(PKIX_List_Create(&infos, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ /*
+ * Traverse the CERTCertificatePolicies structure,
+ * building each PKIX_PL_CertPolicyInfo object in turn
+ */
+ while (*policyInfos != NULL) {
+ CERTPolicyInfo *policyInfo = *policyInfos;
+ CERTPolicyQualifier **policyQualifiers =
+ policyInfo->policyQualifiers;
+ if (policyQualifiers) {
+ /* create a PKIX_List of PKIX_PL_CertPolicyQualifiers */
+ PKIX_CHECK(PKIX_List_Create(&qualifiers, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ while (*policyQualifiers != NULL) {
+ CERTPolicyQualifier *policyQualifier =
+ *policyQualifiers;
+
+ /* create the qualifier's OID object */
+ PKIX_CHECK(PKIX_PL_OID_CreateBySECItem
+ (&policyQualifier->qualifierID,
+ &pkixOID, plContext),
+ PKIX_OIDCREATEFAILED);
+
+ /* create qualifier's ByteArray object */
+
+ PKIX_CHECK(PKIX_PL_ByteArray_Create
+ (policyQualifier->qualifierValue.data,
+ policyQualifier->qualifierValue.len,
+ &qualifierArray,
+ plContext),
+ PKIX_BYTEARRAYCREATEFAILED);
+
+ /* create a CertPolicyQualifier object */
+
+ PKIX_CHECK(pkix_pl_CertPolicyQualifier_Create
+ (pkixOID,
+ qualifierArray,
+ &certPolicyQualifier,
+ plContext),
+ PKIX_CERTPOLICYQUALIFIERCREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (qualifiers,
+ (PKIX_PL_Object *)certPolicyQualifier,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(pkixOID);
+ PKIX_DECREF(qualifierArray);
+ PKIX_DECREF(certPolicyQualifier);
+
+ policyQualifiers++;
+ }
+
+ PKIX_CHECK(PKIX_List_SetImmutable
+ (qualifiers, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+ }
+
+
+ /*
+ * Create an OID object pkixOID from policyInfo->policyID.
+ * (The CERTPolicyInfo structure has an oid field, but it
+ * is of type SECOidTag. This function wants a SECItem.)
+ */
+ PKIX_CHECK(PKIX_PL_OID_CreateBySECItem
+ (&policyInfo->policyID, &pkixOID, plContext),
+ PKIX_OIDCREATEFAILED);
+
+ /* Create a CertPolicyInfo object */
+ PKIX_CHECK(pkix_pl_CertPolicyInfo_Create
+ (pkixOID, qualifiers, &certPolicyInfo, plContext),
+ PKIX_CERTPOLICYINFOCREATEFAILED);
+
+ /* Append the new CertPolicyInfo object to the list */
+ PKIX_CHECK(PKIX_List_AppendItem
+ (infos, (PKIX_PL_Object *)certPolicyInfo, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(pkixOID);
+ PKIX_DECREF(qualifiers);
+ PKIX_DECREF(certPolicyInfo);
+
+ policyInfos++;
+ }
+
+ /*
+ * If there were no policies, we went straight to
+ * cleanup, so we don't have to NULLCHECK infos.
+ */
+ PKIX_CHECK(PKIX_List_SetImmutable(infos, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ *pCertPolicyInfos = infos;
+ infos = NULL;
+
+cleanup:
+ if (certPol) {
+ PKIX_CERT_DEBUG
+ ("\t\tCalling CERT_DestroyCertificatePoliciesExtension).\n");
+ CERT_DestroyCertificatePoliciesExtension(certPol);
+ }
+
+ PKIX_DECREF(infos);
+ PKIX_DECREF(pkixOID);
+ PKIX_DECREF(qualifiers);
+ PKIX_DECREF(certPolicyInfo);
+ PKIX_DECREF(certPolicyQualifier);
+ PKIX_DECREF(qualifierArray);
+
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_DecodePolicyMapping
+ * DESCRIPTION:
+ *
+ * Decodes the contents of the PolicyMapping extension of the CERTCertificate
+ * pointed to by "nssCert", storing the resulting List of CertPolicyMaps at
+ * the address pointed to by "pCertPolicyMaps". If this certificate does not
+ * have a PolicyMapping extension, NULL will be stored. If a List is returned,
+ * it will be immutable.
+ *
+ * PARAMETERS
+ * "nssCert"
+ * Address of the Cert data whose extension is to be examined. Must be
+ * non-NULL.
+ * "pCertPolicyMaps"
+ * Address where the List of CertPolicyMaps will be stored. Must be
+ * non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Cert_DecodePolicyMapping(
+ CERTCertificate *nssCert,
+ PKIX_List **pCertPolicyMaps,
+ void *plContext)
+{
+ SECStatus rv;
+ SECItem encodedCertPolicyMaps;
+
+ /* Allocated in the arena; freed in CERT_Destroy... */
+ CERTCertificatePolicyMappings *certPolMaps = NULL;
+ CERTPolicyMap **policyMaps = NULL;
+
+ /* Holder for the return value */
+ PKIX_List *maps = NULL;
+
+ PKIX_PL_OID *issuerDomainOID = NULL;
+ PKIX_PL_OID *subjectDomainOID = NULL;
+ PKIX_PL_CertPolicyMap *certPolicyMap = NULL;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_DecodePolicyMapping");
+ PKIX_NULLCHECK_TWO(nssCert, pCertPolicyMaps);
+
+ /* get PolicyMappings as a SECItem */
+ PKIX_CERT_DEBUG("\t\tCERT_FindCertExtension).\n");
+ rv = CERT_FindCertExtension
+ (nssCert, SEC_OID_X509_POLICY_MAPPINGS, &encodedCertPolicyMaps);
+ if (SECSuccess != rv) {
+ *pCertPolicyMaps = NULL;
+ goto cleanup;
+ }
+
+ /* translate PolicyMaps to CERTCertificatePolicyMappings */
+ certPolMaps = CERT_DecodePolicyMappingsExtension
+ (&encodedCertPolicyMaps);
+
+ PORT_Free(encodedCertPolicyMaps.data);
+
+ if (!certPolMaps) {
+ PKIX_ERROR(PKIX_CERTDECODEPOLICYMAPPINGSEXTENSIONFAILED);
+ }
+
+ PKIX_NULLCHECK_ONE(certPolMaps->policyMaps);
+
+ policyMaps = certPolMaps->policyMaps;
+
+ /* create a List of CertPolicyMap Objects */
+ PKIX_CHECK(PKIX_List_Create(&maps, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ /*
+ * Traverse the CERTCertificatePolicyMappings structure,
+ * building each CertPolicyMap object in turn
+ */
+ do {
+ CERTPolicyMap *policyMap = *policyMaps;
+
+ /* create the OID for the issuer Domain Policy */
+ PKIX_CHECK(PKIX_PL_OID_CreateBySECItem
+ (&policyMap->issuerDomainPolicy,
+ &issuerDomainOID, plContext),
+ PKIX_OIDCREATEFAILED);
+
+ /* create the OID for the subject Domain Policy */
+ PKIX_CHECK(PKIX_PL_OID_CreateBySECItem
+ (&policyMap->subjectDomainPolicy,
+ &subjectDomainOID, plContext),
+ PKIX_OIDCREATEFAILED);
+
+ /* create the CertPolicyMap */
+
+ PKIX_CHECK(pkix_pl_CertPolicyMap_Create
+ (issuerDomainOID,
+ subjectDomainOID,
+ &certPolicyMap,
+ plContext),
+ PKIX_CERTPOLICYMAPCREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (maps, (PKIX_PL_Object *)certPolicyMap, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(issuerDomainOID);
+ PKIX_DECREF(subjectDomainOID);
+ PKIX_DECREF(certPolicyMap);
+
+ policyMaps++;
+ } while (*policyMaps != NULL);
+
+ PKIX_CHECK(PKIX_List_SetImmutable(maps, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ *pCertPolicyMaps = maps;
+ maps = NULL;
+
+cleanup:
+ if (certPolMaps) {
+ PKIX_CERT_DEBUG
+ ("\t\tCalling CERT_DestroyPolicyMappingsExtension).\n");
+ CERT_DestroyPolicyMappingsExtension(certPolMaps);
+ }
+
+ PKIX_DECREF(maps);
+ PKIX_DECREF(issuerDomainOID);
+ PKIX_DECREF(subjectDomainOID);
+ PKIX_DECREF(certPolicyMap);
+
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_DecodePolicyConstraints
+ * DESCRIPTION:
+ *
+ * Decodes the contents of the PolicyConstraints extension in the
+ * CERTCertificate pointed to by "nssCert", to obtain SkipCerts values
+ * which are stored at the addresses "pExplicitPolicySkipCerts" and
+ * "pInhibitMappingSkipCerts", respectively. If this certificate does
+ * not have an PolicyConstraints extension, or if either of the optional
+ * components is not supplied, this function stores a value of -1 for any
+ * missing component.
+ *
+ * PARAMETERS
+ * "nssCert"
+ * Address of the Cert data whose extension is to be examined. Must be
+ * non-NULL.
+ * "pExplicitPolicySkipCerts"
+ * Address where the SkipCert value for the requireExplicitPolicy
+ * component will be stored. Must be non-NULL.
+ * "pInhibitMappingSkipCerts"
+ * Address where the SkipCert value for the inhibitPolicyMapping
+ * component will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Cert_DecodePolicyConstraints(
+ CERTCertificate *nssCert,
+ PKIX_Int32 *pExplicitPolicySkipCerts,
+ PKIX_Int32 *pInhibitMappingSkipCerts,
+ void *plContext)
+{
+ CERTCertificatePolicyConstraints policyConstraints;
+ SECStatus rv;
+ SECItem encodedCertPolicyConstraints;
+ PKIX_Int32 explicitPolicySkipCerts = -1;
+ PKIX_Int32 inhibitMappingSkipCerts = -1;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_DecodePolicyConstraints");
+ PKIX_NULLCHECK_THREE
+ (nssCert, pExplicitPolicySkipCerts, pInhibitMappingSkipCerts);
+
+ /* get the two skipCert values as SECItems */
+ PKIX_CERT_DEBUG("\t\tCalling CERT_FindCertExtension).\n");
+ rv = CERT_FindCertExtension
+ (nssCert,
+ SEC_OID_X509_POLICY_CONSTRAINTS,
+ &encodedCertPolicyConstraints);
+
+ if (rv == SECSuccess) {
+
+ policyConstraints.explicitPolicySkipCerts.data =
+ (unsigned char *)&explicitPolicySkipCerts;
+ policyConstraints.inhibitMappingSkipCerts.data =
+ (unsigned char *)&inhibitMappingSkipCerts;
+
+ /* translate DER to CERTCertificatePolicyConstraints */
+ rv = CERT_DecodePolicyConstraintsExtension
+ (&policyConstraints, &encodedCertPolicyConstraints);
+
+ PORT_Free(encodedCertPolicyConstraints.data);
+
+ if (rv != SECSuccess) {
+ PKIX_ERROR
+ (PKIX_CERTDECODEPOLICYCONSTRAINTSEXTENSIONFAILED);
+ }
+ }
+
+ *pExplicitPolicySkipCerts = explicitPolicySkipCerts;
+ *pInhibitMappingSkipCerts = inhibitMappingSkipCerts;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_DecodeInhibitAnyPolicy
+ * DESCRIPTION:
+ *
+ * Decodes the contents of the InhibitAnyPolicy extension in the
+ * CERTCertificate pointed to by "nssCert", to obtain a SkipCerts value,
+ * which is stored at the address "pSkipCerts". If this certificate does
+ * not have an InhibitAnyPolicy extension, -1 will be stored.
+ *
+ * PARAMETERS
+ * "nssCert"
+ * Address of the Cert data whose InhibitAnyPolicy extension is to be
+ * processed. Must be non-NULL.
+ * "pSkipCerts"
+ * Address where the SkipCert value from the InhibitAnyPolicy extension
+ * will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Cert_DecodeInhibitAnyPolicy(
+ CERTCertificate *nssCert,
+ PKIX_Int32 *pSkipCerts,
+ void *plContext)
+{
+ CERTCertificateInhibitAny inhibitAny;
+ SECStatus rv;
+ SECItem encodedCertInhibitAny;
+ PKIX_Int32 skipCerts = -1;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_DecodeInhibitAnyPolicy");
+ PKIX_NULLCHECK_TWO(nssCert, pSkipCerts);
+
+ /* get InhibitAny as a SECItem */
+ PKIX_CERT_DEBUG("\t\tCalling CERT_FindCertExtension).\n");
+ rv = CERT_FindCertExtension
+ (nssCert, SEC_OID_X509_INHIBIT_ANY_POLICY, &encodedCertInhibitAny);
+
+ if (rv == SECSuccess) {
+ inhibitAny.inhibitAnySkipCerts.data =
+ (unsigned char *)&skipCerts;
+
+ /* translate DER to CERTCertificateInhibitAny */
+ rv = CERT_DecodeInhibitAnyExtension
+ (&inhibitAny, &encodedCertInhibitAny);
+
+ PORT_Free(encodedCertInhibitAny.data);
+
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_CERTDECODEINHIBITANYEXTENSIONFAILED);
+ }
+ }
+
+ *pSkipCerts = skipCerts;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_GetNssSubjectAltNames
+ * DESCRIPTION:
+ *
+ * Retrieves the Subject Alternative Names of the certificate specified by
+ * "cert" and stores it at "pNssSubjAltNames". If the Subject Alternative
+ * Name extension is not present, NULL is returned at "pNssSubjAltNames".
+ * If the Subject Alternative Names has not been previously decoded, it is
+ * decoded here with lock on the "cert" unless the flag "hasLock" indicates
+ * the lock had been obtained at a higher call level.
+ *
+ * PARAMETERS
+ * "cert"
+ * Address of the certificate whose Subject Alternative Names extensions
+ * is retrieved. Must be non-NULL.
+ * "hasLock"
+ * Boolean indicates caller has acquired a lock.
+ * Must be non-NULL.
+ * "pNssSubjAltNames"
+ * Address where the returned Subject Alternative Names will be stored.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Cert_GetNssSubjectAltNames(
+ PKIX_PL_Cert *cert,
+ PKIX_Boolean hasLock,
+ CERTGeneralName **pNssSubjAltNames,
+ void *plContext)
+{
+ CERTCertificate *nssCert = NULL;
+ CERTGeneralName *nssOriginalAltName = NULL;
+ PLArenaPool *arena = NULL;
+ SECItem altNameExtension = {siBuffer, NULL, 0};
+ SECStatus rv = SECFailure;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_GetNssSubjectAltNames");
+ PKIX_NULLCHECK_THREE(cert, pNssSubjAltNames, cert->nssCert);
+
+ nssCert = cert->nssCert;
+
+ if ((cert->nssSubjAltNames == NULL) && (!cert->subjAltNamesAbsent)){
+
+ if (!hasLock) {
+ PKIX_OBJECT_LOCK(cert);
+ }
+
+ if ((cert->nssSubjAltNames == NULL) &&
+ (!cert->subjAltNamesAbsent)){
+
+ PKIX_PL_NSSCALLRV(CERT, rv, CERT_FindCertExtension,
+ (nssCert,
+ SEC_OID_X509_SUBJECT_ALT_NAME,
+ &altNameExtension));
+
+ if (rv != SECSuccess) {
+ *pNssSubjAltNames = NULL;
+ cert->subjAltNamesAbsent = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ if (cert->arenaNameConstraints == NULL) {
+ PKIX_PL_NSSCALLRV(CERT, arena, PORT_NewArena,
+ (DER_DEFAULT_CHUNKSIZE));
+
+ if (arena == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+ cert->arenaNameConstraints = arena;
+ }
+
+ PKIX_PL_NSSCALLRV
+ (CERT,
+ nssOriginalAltName,
+ (CERTGeneralName *) CERT_DecodeAltNameExtension,
+ (cert->arenaNameConstraints, &altNameExtension));
+
+ PKIX_PL_NSSCALL(CERT, PORT_Free, (altNameExtension.data));
+
+ if (nssOriginalAltName == NULL) {
+ PKIX_ERROR(PKIX_CERTDECODEALTNAMEEXTENSIONFAILED);
+ }
+ cert->nssSubjAltNames = nssOriginalAltName;
+
+ }
+
+ if (!hasLock) {
+ PKIX_OBJECT_UNLOCK(cert);
+ }
+ }
+
+ *pNssSubjAltNames = cert->nssSubjAltNames;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_CheckExtendKeyUsage
+ * DESCRIPTION:
+ *
+ * For each of the ON bit in "requiredExtendedKeyUsages" that represents its
+ * SECCertUsageEnum type, this function checks "cert"'s certType (extended
+ * key usage) and key usage with what is required for SECCertUsageEnum type.
+ *
+ * PARAMETERS
+ * "cert"
+ * Address of the certificate whose Extended Key Usage extensions
+ * is retrieved. Must be non-NULL.
+ * "requiredExtendedKeyUsages"
+ * An unsigned integer, its bit location is ON based on the required key
+ * usage value representing in SECCertUsageEnum.
+ * "pPass"
+ * Address where the return value, indicating key usage check passed, is
+ * stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Cert_CheckExtendedKeyUsage(
+ PKIX_PL_Cert *cert,
+ PKIX_UInt32 requiredExtendedKeyUsages,
+ PKIX_Boolean *pPass,
+ void *plContext)
+{
+ PKIX_PL_CertBasicConstraints *basicConstraints = NULL;
+ PKIX_UInt32 certType = 0;
+ PKIX_UInt32 requiredKeyUsage = 0;
+ PKIX_UInt32 requiredCertType = 0;
+ PKIX_UInt32 requiredExtendedKeyUsage = 0;
+ PKIX_UInt32 i;
+ PKIX_Boolean isCA = PKIX_FALSE;
+ SECStatus rv = SECFailure;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_CheckExtendKeyUsage");
+ PKIX_NULLCHECK_THREE(cert, pPass, cert->nssCert);
+
+ *pPass = PKIX_FALSE;
+
+ PKIX_CERT_DEBUG("\t\tCalling cert_GetCertType).\n");
+ cert_GetCertType(cert->nssCert);
+ certType = cert->nssCert->nsCertType;
+
+ PKIX_CHECK(PKIX_PL_Cert_GetBasicConstraints
+ (cert,
+ &basicConstraints,
+ plContext),
+ PKIX_CERTGETBASICCONSTRAINTFAILED);
+
+ if (basicConstraints != NULL) {
+ PKIX_CHECK(PKIX_PL_BasicConstraints_GetCAFlag
+ (basicConstraints, &isCA, plContext),
+ PKIX_BASICCONSTRAINTSGETCAFLAGFAILED);
+ }
+
+ i = 0;
+ while (requiredExtendedKeyUsages != 0) {
+
+ /* Find the bit location of the right-most non-zero bit */
+ while (requiredExtendedKeyUsages != 0) {
+ if (((1 << i) & requiredExtendedKeyUsages) != 0) {
+ requiredExtendedKeyUsage = 1 << i;
+ break;
+ }
+ i++;
+ }
+ requiredExtendedKeyUsages ^= requiredExtendedKeyUsage;
+
+ requiredExtendedKeyUsage = i;
+
+ PKIX_PL_NSSCALLRV(CERT, rv, CERT_KeyUsageAndTypeForCertUsage,
+ (requiredExtendedKeyUsage,
+ isCA,
+ &requiredKeyUsage,
+ &requiredCertType));
+
+ if (!(certType & requiredCertType)) {
+ goto cleanup;
+ }
+
+ PKIX_PL_NSSCALLRV(CERT, rv, CERT_CheckKeyUsage,
+ (cert->nssCert, requiredKeyUsage));
+ if (rv != SECSuccess) {
+ goto cleanup;
+ }
+ i++;
+
+ }
+
+ *pPass = PKIX_TRUE;
+
+cleanup:
+ PKIX_DECREF(basicConstraints);
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_ToString_Helper
+ * DESCRIPTION:
+ *
+ * Helper function that creates a string representation of the Cert pointed
+ * to by "cert" and stores it at "pString", where the value of
+ * "partialString" determines whether a full or partial representation of
+ * the Cert is stored.
+ *
+ * PARAMETERS
+ * "cert"
+ * Address of Cert whose string representation is desired.
+ * Must be non-NULL.
+ * "partialString"
+ * Boolean indicating whether a partial Cert representation is desired.
+ * "pString"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Cert_ToString_Helper(
+ PKIX_PL_Cert *cert,
+ PKIX_Boolean partialString,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_String *certString = NULL;
+ char *asciiFormat = NULL;
+ PKIX_PL_String *formatString = NULL;
+ PKIX_UInt32 certVersion;
+ PKIX_PL_BigInt *certSN = NULL;
+ PKIX_PL_String *certSNString = NULL;
+ PKIX_PL_X500Name *certIssuer = NULL;
+ PKIX_PL_String *certIssuerString = NULL;
+ PKIX_PL_X500Name *certSubject = NULL;
+ PKIX_PL_String *certSubjectString = NULL;
+ PKIX_PL_String *notBeforeString = NULL;
+ PKIX_PL_String *notAfterString = NULL;
+ PKIX_List *subjAltNames = NULL;
+ PKIX_PL_String *subjAltNamesString = NULL;
+ PKIX_PL_ByteArray *authKeyId = NULL;
+ PKIX_PL_String *authKeyIdString = NULL;
+ PKIX_PL_ByteArray *subjKeyId = NULL;
+ PKIX_PL_String *subjKeyIdString = NULL;
+ PKIX_PL_PublicKey *nssPubKey = NULL;
+ PKIX_PL_String *nssPubKeyString = NULL;
+ PKIX_List *critExtOIDs = NULL;
+ PKIX_PL_String *critExtOIDsString = NULL;
+ PKIX_List *extKeyUsages = NULL;
+ PKIX_PL_String *extKeyUsagesString = NULL;
+ PKIX_PL_CertBasicConstraints *basicConstraint = NULL;
+ PKIX_PL_String *certBasicConstraintsString = NULL;
+ PKIX_List *policyInfo = NULL;
+ PKIX_PL_String *certPolicyInfoString = NULL;
+ PKIX_List *certPolicyMappings = NULL;
+ PKIX_PL_String *certPolicyMappingsString = NULL;
+ PKIX_Int32 certExplicitPolicy = 0;
+ PKIX_Int32 certInhibitMapping = 0;
+ PKIX_Int32 certInhibitAnyPolicy = 0;
+ PKIX_PL_CertNameConstraints *nameConstraints = NULL;
+ PKIX_PL_String *nameConstraintsString = NULL;
+ PKIX_List *authorityInfoAccess = NULL;
+ PKIX_PL_String *authorityInfoAccessString = NULL;
+ PKIX_List *subjectInfoAccess = NULL;
+ PKIX_PL_String *subjectInfoAccessString = NULL;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_ToString_Helper");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pString);
+
+ /*
+ * XXX Add to this format as certificate components are developed.
+ */
+
+ if (partialString){
+ asciiFormat =
+ "\t[Issuer: %s\n"
+ "\t Subject: %s]";
+ } else {
+ asciiFormat =
+ "[\n"
+ "\tVersion: v%d\n"
+ "\tSerialNumber: %s\n"
+ "\tIssuer: %s\n"
+ "\tSubject: %s\n"
+ "\tValidity: [From: %s\n"
+ "\t To: %s]\n"
+ "\tSubjectAltNames: %s\n"
+ "\tAuthorityKeyId: %s\n"
+ "\tSubjectKeyId: %s\n"
+ "\tSubjPubKeyAlgId: %s\n"
+ "\tCritExtOIDs: %s\n"
+ "\tExtKeyUsages: %s\n"
+ "\tBasicConstraint: %s\n"
+ "\tCertPolicyInfo: %s\n"
+ "\tPolicyMappings: %s\n"
+ "\tExplicitPolicy: %d\n"
+ "\tInhibitMapping: %d\n"
+ "\tInhibitAnyPolicy:%d\n"
+ "\tNameConstraints: %s\n"
+ "\tAuthorityInfoAccess: %s\n"
+ "\tSubjectInfoAccess: %s\n"
+ "\tCacheFlag: %d\n"
+ "]\n";
+ }
+
+
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, asciiFormat, 0, &formatString, plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ /* Issuer */
+ PKIX_CHECK(PKIX_PL_Cert_GetIssuer
+ (cert, &certIssuer, plContext),
+ PKIX_CERTGETISSUERFAILED);
+
+ PKIX_CHECK(PKIX_PL_Object_ToString
+ ((PKIX_PL_Object *)certIssuer, &certIssuerString, plContext),
+ PKIX_X500NAMETOSTRINGFAILED);
+
+ /* Subject */
+ PKIX_CHECK(PKIX_PL_Cert_GetSubject(cert, &certSubject, plContext),
+ PKIX_CERTGETSUBJECTFAILED);
+
+ PKIX_TOSTRING(certSubject, &certSubjectString, plContext,
+ PKIX_X500NAMETOSTRINGFAILED);
+
+ if (partialString){
+ PKIX_CHECK(PKIX_PL_Sprintf
+ (&certString,
+ plContext,
+ formatString,
+ certIssuerString,
+ certSubjectString),
+ PKIX_SPRINTFFAILED);
+
+ *pString = certString;
+ goto cleanup;
+ }
+
+ /* Version */
+ PKIX_CHECK(PKIX_PL_Cert_GetVersion(cert, &certVersion, plContext),
+ PKIX_CERTGETVERSIONFAILED);
+
+ /* SerialNumber */
+ PKIX_CHECK(PKIX_PL_Cert_GetSerialNumber(cert, &certSN, plContext),
+ PKIX_CERTGETSERIALNUMBERFAILED);
+
+ PKIX_CHECK(PKIX_PL_Object_ToString
+ ((PKIX_PL_Object *)certSN, &certSNString, plContext),
+ PKIX_BIGINTTOSTRINGFAILED);
+
+ /* Validity: NotBefore */
+ PKIX_CHECK(pkix_pl_Date_ToString_Helper
+ (&(cert->nssCert->validity.notBefore),
+ &notBeforeString,
+ plContext),
+ PKIX_DATETOSTRINGHELPERFAILED);
+
+ /* Validity: NotAfter */
+ PKIX_CHECK(pkix_pl_Date_ToString_Helper
+ (&(cert->nssCert->validity.notAfter),
+ &notAfterString,
+ plContext),
+ PKIX_DATETOSTRINGHELPERFAILED);
+
+ /* SubjectAltNames */
+ PKIX_CHECK(PKIX_PL_Cert_GetSubjectAltNames
+ (cert, &subjAltNames, plContext),
+ PKIX_CERTGETSUBJECTALTNAMESFAILED);
+
+ PKIX_TOSTRING(subjAltNames, &subjAltNamesString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ /* AuthorityKeyIdentifier */
+ PKIX_CHECK(PKIX_PL_Cert_GetAuthorityKeyIdentifier
+ (cert, &authKeyId, plContext),
+ PKIX_CERTGETAUTHORITYKEYIDENTIFIERFAILED);
+
+ PKIX_TOSTRING(authKeyId, &authKeyIdString, plContext,
+ PKIX_BYTEARRAYTOSTRINGFAILED);
+
+ /* SubjectKeyIdentifier */
+ PKIX_CHECK(PKIX_PL_Cert_GetSubjectKeyIdentifier
+ (cert, &subjKeyId, plContext),
+ PKIX_CERTGETSUBJECTKEYIDENTIFIERFAILED);
+
+ PKIX_TOSTRING(subjKeyId, &subjKeyIdString, plContext,
+ PKIX_BYTEARRAYTOSTRINGFAILED);
+
+ /* SubjectPublicKey */
+ PKIX_CHECK(PKIX_PL_Cert_GetSubjectPublicKey
+ (cert, &nssPubKey, plContext),
+ PKIX_CERTGETSUBJECTPUBLICKEYFAILED);
+
+ PKIX_CHECK(PKIX_PL_Object_ToString
+ ((PKIX_PL_Object *)nssPubKey, &nssPubKeyString, plContext),
+ PKIX_PUBLICKEYTOSTRINGFAILED);
+
+ /* CriticalExtensionOIDs */
+ PKIX_CHECK(PKIX_PL_Cert_GetCriticalExtensionOIDs
+ (cert, &critExtOIDs, plContext),
+ PKIX_CERTGETCRITICALEXTENSIONOIDSFAILED);
+
+ PKIX_TOSTRING(critExtOIDs, &critExtOIDsString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ /* ExtendedKeyUsages */
+ PKIX_CHECK(PKIX_PL_Cert_GetExtendedKeyUsage
+ (cert, &extKeyUsages, plContext),
+ PKIX_CERTGETEXTENDEDKEYUSAGEFAILED);
+
+ PKIX_TOSTRING(extKeyUsages, &extKeyUsagesString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ /* CertBasicConstraints */
+ PKIX_CHECK(PKIX_PL_Cert_GetBasicConstraints
+ (cert, &basicConstraint, plContext),
+ PKIX_CERTGETBASICCONSTRAINTSFAILED);
+
+ PKIX_TOSTRING(basicConstraint, &certBasicConstraintsString, plContext,
+ PKIX_CERTBASICCONSTRAINTSTOSTRINGFAILED);
+
+ /* CertPolicyInfo */
+ PKIX_CHECK(PKIX_PL_Cert_GetPolicyInformation
+ (cert, &policyInfo, plContext),
+ PKIX_CERTGETPOLICYINFORMATIONFAILED);
+
+ PKIX_TOSTRING(policyInfo, &certPolicyInfoString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ /* Advanced Policies */
+ PKIX_CHECK(PKIX_PL_Cert_GetPolicyMappings
+ (cert, &certPolicyMappings, plContext),
+ PKIX_CERTGETPOLICYMAPPINGSFAILED);
+
+ PKIX_TOSTRING(certPolicyMappings, &certPolicyMappingsString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ PKIX_CHECK(PKIX_PL_Cert_GetRequireExplicitPolicy
+ (cert, &certExplicitPolicy, plContext),
+ PKIX_CERTGETREQUIREEXPLICITPOLICYFAILED);
+
+ PKIX_CHECK(PKIX_PL_Cert_GetPolicyMappingInhibited
+ (cert, &certInhibitMapping, plContext),
+ PKIX_CERTGETPOLICYMAPPINGINHIBITEDFAILED);
+
+ PKIX_CHECK(PKIX_PL_Cert_GetInhibitAnyPolicy
+ (cert, &certInhibitAnyPolicy, plContext),
+ PKIX_CERTGETINHIBITANYPOLICYFAILED);
+
+ /* Name Constraints */
+ PKIX_CHECK(PKIX_PL_Cert_GetNameConstraints
+ (cert, &nameConstraints, plContext),
+ PKIX_CERTGETNAMECONSTRAINTSFAILED);
+
+ PKIX_TOSTRING(nameConstraints, &nameConstraintsString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ /* Authority Information Access */
+ PKIX_CHECK(PKIX_PL_Cert_GetAuthorityInfoAccess
+ (cert, &authorityInfoAccess, plContext),
+ PKIX_CERTGETAUTHORITYINFOACCESSFAILED);
+
+ PKIX_TOSTRING(authorityInfoAccess, &authorityInfoAccessString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ /* Subject Information Access */
+ PKIX_CHECK(PKIX_PL_Cert_GetSubjectInfoAccess
+ (cert, &subjectInfoAccess, plContext),
+ PKIX_CERTGETSUBJECTINFOACCESSFAILED);
+
+ PKIX_TOSTRING(subjectInfoAccess, &subjectInfoAccessString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ PKIX_CHECK(PKIX_PL_Sprintf
+ (&certString,
+ plContext,
+ formatString,
+ certVersion + 1,
+ certSNString,
+ certIssuerString,
+ certSubjectString,
+ notBeforeString,
+ notAfterString,
+ subjAltNamesString,
+ authKeyIdString,
+ subjKeyIdString,
+ nssPubKeyString,
+ critExtOIDsString,
+ extKeyUsagesString,
+ certBasicConstraintsString,
+ certPolicyInfoString,
+ certPolicyMappingsString,
+ certExplicitPolicy, /* an Int32, not a String */
+ certInhibitMapping, /* an Int32, not a String */
+ certInhibitAnyPolicy, /* an Int32, not a String */
+ nameConstraintsString,
+ authorityInfoAccessString,
+ subjectInfoAccessString,
+ cert->cacheFlag), /* a boolean */
+ PKIX_SPRINTFFAILED);
+
+ *pString = certString;
+
+cleanup:
+ PKIX_DECREF(certSN);
+ PKIX_DECREF(certSNString);
+ PKIX_DECREF(certIssuer);
+ PKIX_DECREF(certIssuerString);
+ PKIX_DECREF(certSubject);
+ PKIX_DECREF(certSubjectString);
+ PKIX_DECREF(notBeforeString);
+ PKIX_DECREF(notAfterString);
+ PKIX_DECREF(subjAltNames);
+ PKIX_DECREF(subjAltNamesString);
+ PKIX_DECREF(authKeyId);
+ PKIX_DECREF(authKeyIdString);
+ PKIX_DECREF(subjKeyId);
+ PKIX_DECREF(subjKeyIdString);
+ PKIX_DECREF(nssPubKey);
+ PKIX_DECREF(nssPubKeyString);
+ PKIX_DECREF(critExtOIDs);
+ PKIX_DECREF(critExtOIDsString);
+ PKIX_DECREF(extKeyUsages);
+ PKIX_DECREF(extKeyUsagesString);
+ PKIX_DECREF(basicConstraint);
+ PKIX_DECREF(certBasicConstraintsString);
+ PKIX_DECREF(policyInfo);
+ PKIX_DECREF(certPolicyInfoString);
+ PKIX_DECREF(certPolicyMappings);
+ PKIX_DECREF(certPolicyMappingsString);
+ PKIX_DECREF(nameConstraints);
+ PKIX_DECREF(nameConstraintsString);
+ PKIX_DECREF(authorityInfoAccess);
+ PKIX_DECREF(authorityInfoAccessString);
+ PKIX_DECREF(subjectInfoAccess);
+ PKIX_DECREF(subjectInfoAccessString);
+ PKIX_DECREF(formatString);
+
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Cert_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_Cert *cert = NULL;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CERT_TYPE, plContext),
+ PKIX_OBJECTNOTCERT);
+
+ cert = (PKIX_PL_Cert*)object;
+
+ PKIX_DECREF(cert->subject);
+ PKIX_DECREF(cert->issuer);
+ PKIX_DECREF(cert->subjAltNames);
+ PKIX_DECREF(cert->publicKeyAlgId);
+ PKIX_DECREF(cert->publicKey);
+ PKIX_DECREF(cert->serialNumber);
+ PKIX_DECREF(cert->critExtOids);
+ PKIX_DECREF(cert->authKeyId);
+ PKIX_DECREF(cert->subjKeyId);
+ PKIX_DECREF(cert->extKeyUsages);
+ PKIX_DECREF(cert->certBasicConstraints);
+ PKIX_DECREF(cert->certPolicyInfos);
+ PKIX_DECREF(cert->certPolicyMappings);
+ PKIX_DECREF(cert->nameConstraints);
+ PKIX_DECREF(cert->store);
+ PKIX_DECREF(cert->authorityInfoAccess);
+ PKIX_DECREF(cert->subjectInfoAccess);
+ PKIX_DECREF(cert->crldpList);
+
+ if (cert->arenaNameConstraints){
+ /* This arena was allocated for SubjectAltNames */
+ PKIX_PL_NSSCALL(CERT, PORT_FreeArena,
+ (cert->arenaNameConstraints, PR_FALSE));
+
+ cert->arenaNameConstraints = NULL;
+ cert->nssSubjAltNames = NULL;
+ }
+
+ CERT_DestroyCertificate(cert->nssCert);
+ cert->nssCert = NULL;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Cert_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_String *certString = NULL;
+ PKIX_PL_Cert *pkixCert = NULL;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_toString");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CERT_TYPE, plContext),
+ PKIX_OBJECTNOTCERT);
+
+ pkixCert = (PKIX_PL_Cert *)object;
+
+ PKIX_CHECK(pkix_pl_Cert_ToString_Helper
+ (pkixCert, PKIX_FALSE, &certString, plContext),
+ PKIX_CERTTOSTRINGHELPERFAILED);
+
+ *pString = certString;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Cert_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_Cert *pkixCert = NULL;
+ CERTCertificate *nssCert = NULL;
+ unsigned char *derBytes = NULL;
+ PKIX_UInt32 derLength;
+ PKIX_UInt32 certHash;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CERT_TYPE, plContext),
+ PKIX_OBJECTNOTCERT);
+
+ pkixCert = (PKIX_PL_Cert *)object;
+
+ nssCert = pkixCert->nssCert;
+ derBytes = (nssCert->derCert).data;
+ derLength = (nssCert->derCert).len;
+
+ PKIX_CHECK(pkix_hash(derBytes, derLength, &certHash, plContext),
+ PKIX_HASHFAILED);
+
+ *pHashcode = certHash;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_Cert_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Cert_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ CERTCertificate *firstCert = NULL;
+ CERTCertificate *secondCert = NULL;
+ PKIX_UInt32 secondType;
+ PKIX_Boolean cmpResult;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ /* test that firstObject is a Cert */
+ PKIX_CHECK(pkix_CheckType(firstObject, PKIX_CERT_TYPE, plContext),
+ PKIX_FIRSTOBJECTNOTCERT);
+
+ /*
+ * Since we know firstObject is a Cert, if both references are
+ * identical, they must be equal
+ */
+ if (firstObject == secondObject){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondObject isn't a Cert, we don't throw an error.
+ * We simply return a Boolean result of FALSE
+ */
+ *pResult = PKIX_FALSE;
+ PKIX_CHECK(PKIX_PL_Object_GetType
+ (secondObject, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+ if (secondType != PKIX_CERT_TYPE) goto cleanup;
+
+ firstCert = ((PKIX_PL_Cert *)firstObject)->nssCert;
+ secondCert = ((PKIX_PL_Cert *)secondObject)->nssCert;
+
+ PKIX_NULLCHECK_TWO(firstCert, secondCert);
+
+ /* CERT_CompareCerts does byte comparison on DER encodings of certs */
+ PKIX_CERT_DEBUG("\t\tCalling CERT_CompareCerts).\n");
+ cmpResult = CERT_CompareCerts(firstCert, secondCert);
+
+ *pResult = cmpResult;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_CERT_TYPE and its related functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_Cert_RegisterSelf(void *plContext)
+{
+
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_RegisterSelf");
+
+ entry.description = "Cert";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_Cert);
+ entry.destructor = pkix_pl_Cert_Destroy;
+ entry.equalsFunction = pkix_pl_Cert_Equals;
+ entry.hashcodeFunction = pkix_pl_Cert_Hashcode;
+ entry.toStringFunction = pkix_pl_Cert_ToString;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_CERT_TYPE] = entry;
+
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_CreateWithNSSCert
+ * DESCRIPTION:
+ *
+ * Creates a new certificate using the CERTCertificate pointed to by "nssCert"
+ * and stores it at "pCert". Once created, a Cert is immutable.
+ *
+ * This function is primarily used as a convenience function for the
+ * performance tests that have easy access to a CERTCertificate.
+ *
+ * PARAMETERS:
+ * "nssCert"
+ * Address of CERTCertificate representing the NSS certificate.
+ * Must be non-NULL.
+ * "pCert"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Cert_CreateWithNSSCert(
+ CERTCertificate *nssCert,
+ PKIX_PL_Cert **pCert,
+ void *plContext)
+{
+ PKIX_PL_Cert *cert = NULL;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_CreateWithNSSCert");
+ PKIX_NULLCHECK_TWO(pCert, nssCert);
+
+ /* create a PKIX_PL_Cert object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_CERT_TYPE,
+ sizeof (PKIX_PL_Cert),
+ (PKIX_PL_Object **)&cert,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ /* populate the nssCert field */
+ cert->nssCert = nssCert;
+
+ /* initialize remaining fields */
+ /*
+ * Fields ending with Absent are initialized to PKIX_FALSE so that the
+ * first time we need the value we will look for it. If we find it is
+ * actually absent, the flag will at that time be set to PKIX_TRUE to
+ * prevent searching for it later.
+ * Fields ending with Processed are those where a value is defined
+ * for the Absent case, and a value of zero is possible. When the
+ * flag is still true we have to look for the field, set the default
+ * value if necessary, and set the Processed flag to PKIX_TRUE.
+ */
+ cert->subject = NULL;
+ cert->issuer = NULL;
+ cert->subjAltNames = NULL;
+ cert->subjAltNamesAbsent = PKIX_FALSE;
+ cert->publicKeyAlgId = NULL;
+ cert->publicKey = NULL;
+ cert->serialNumber = NULL;
+ cert->critExtOids = NULL;
+ cert->subjKeyId = NULL;
+ cert->subjKeyIdAbsent = PKIX_FALSE;
+ cert->authKeyId = NULL;
+ cert->authKeyIdAbsent = PKIX_FALSE;
+ cert->extKeyUsages = NULL;
+ cert->extKeyUsagesAbsent = PKIX_FALSE;
+ cert->certBasicConstraints = NULL;
+ cert->basicConstraintsAbsent = PKIX_FALSE;
+ cert->certPolicyInfos = NULL;
+ cert->policyInfoAbsent = PKIX_FALSE;
+ cert->policyMappingsAbsent = PKIX_FALSE;
+ cert->certPolicyMappings = NULL;
+ cert->policyConstraintsProcessed = PKIX_FALSE;
+ cert->policyConstraintsExplicitPolicySkipCerts = 0;
+ cert->policyConstraintsInhibitMappingSkipCerts = 0;
+ cert->inhibitAnyPolicyProcessed = PKIX_FALSE;
+ cert->inhibitAnySkipCerts = 0;
+ cert->nameConstraints = NULL;
+ cert->nameConstraintsAbsent = PKIX_FALSE;
+ cert->arenaNameConstraints = NULL;
+ cert->nssSubjAltNames = NULL;
+ cert->cacheFlag = PKIX_FALSE;
+ cert->store = NULL;
+ cert->authorityInfoAccess = NULL;
+ cert->subjectInfoAccess = NULL;
+ cert->isUserTrustAnchor = PKIX_FALSE;
+ cert->crldpList = NULL;
+
+ *pCert = cert;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Cert_CreateToList
+ * DESCRIPTION:
+ *
+ * Creates a new certificate using the DER-encoding pointed to by "derCertItem"
+ * and appends it to the list pointed to by "certList". If Cert creation fails,
+ * the function returns with certList unchanged, but any decoding Error is
+ * discarded.
+ *
+ * PARAMETERS:
+ * "derCertItem"
+ * Address of SECItem containing the DER representation of a certificate.
+ * Must be non-NULL.
+ * "certList"
+ * Address of List to which the Cert will be appended, if successfully
+ * created. May be empty, but must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Cert_CreateToList(
+ SECItem *derCertItem,
+ PKIX_List *certList,
+ void *plContext)
+{
+ CERTCertificate *nssCert = NULL;
+ PKIX_PL_Cert *cert = NULL;
+ CERTCertDBHandle *handle;
+
+ PKIX_ENTER(CERT, "pkix_pl_Cert_CreateToList");
+ PKIX_NULLCHECK_TWO(derCertItem, certList);
+
+ handle = CERT_GetDefaultCertDB();
+ nssCert = CERT_NewTempCertificate(handle, derCertItem,
+ /* nickname */ NULL,
+ /* isPerm */ PR_FALSE,
+ /* copyDer */ PR_TRUE);
+ if (!nssCert) {
+ goto cleanup;
+ }
+
+ PKIX_CHECK(pkix_pl_Cert_CreateWithNSSCert
+ (nssCert, &cert, plContext),
+ PKIX_CERTCREATEWITHNSSCERTFAILED);
+
+ nssCert = NULL;
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (certList, (PKIX_PL_Object *) cert, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+cleanup:
+ if (nssCert) {
+ CERT_DestroyCertificate(nssCert);
+ }
+
+ PKIX_DECREF(cert);
+ PKIX_RETURN(CERT);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_Cert_Create (see comments in pkix_pl_pki.h)
+ * XXX We may want to cache the cert after parsing it, so it can be reused
+ * XXX Are the NSS/NSPR functions thread safe
+ */
+PKIX_Error *
+PKIX_PL_Cert_Create(
+ PKIX_PL_ByteArray *byteArray,
+ PKIX_PL_Cert **pCert,
+ void *plContext)
+{
+ CERTCertificate *nssCert = NULL;
+ SECItem *derCertItem = NULL;
+ void *derBytes = NULL;
+ PKIX_UInt32 derLength;
+ PKIX_PL_Cert *cert = NULL;
+ CERTCertDBHandle *handle;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_Create");
+ PKIX_NULLCHECK_TWO(pCert, byteArray);
+
+ PKIX_CHECK(PKIX_PL_ByteArray_GetPointer
+ (byteArray, &derBytes, plContext),
+ PKIX_BYTEARRAYGETPOINTERFAILED);
+
+ PKIX_CHECK(PKIX_PL_ByteArray_GetLength
+ (byteArray, &derLength, plContext),
+ PKIX_BYTEARRAYGETLENGTHFAILED);
+
+ derCertItem = SECITEM_AllocItem(NULL, NULL, derLength);
+ if (derCertItem == NULL){
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ (void) PORT_Memcpy(derCertItem->data, derBytes, derLength);
+
+ /*
+ * setting copyDER to true forces NSS to make its own copy of the DER,
+ * allowing us to free our copy without worrying about whether NSS
+ * is still using it
+ */
+ handle = CERT_GetDefaultCertDB();
+ nssCert = CERT_NewTempCertificate(handle, derCertItem,
+ /* nickname */ NULL,
+ /* isPerm */ PR_FALSE,
+ /* copyDer */ PR_TRUE);
+ if (!nssCert){
+ PKIX_ERROR(PKIX_CERTDECODEDERCERTIFICATEFAILED);
+ }
+
+ PKIX_CHECK(pkix_pl_Cert_CreateWithNSSCert
+ (nssCert, &cert, plContext),
+ PKIX_CERTCREATEWITHNSSCERTFAILED);
+
+ *pCert = cert;
+
+cleanup:
+ if (derCertItem){
+ SECITEM_FreeItem(derCertItem, PKIX_TRUE);
+ }
+
+ if (nssCert && PKIX_ERROR_RECEIVED){
+ PKIX_CERT_DEBUG("\t\tCalling CERT_DestroyCertificate).\n");
+ CERT_DestroyCertificate(nssCert);
+ nssCert = NULL;
+ }
+
+ PKIX_FREE(derBytes);
+ PKIX_RETURN(CERT);
+}
+
+
+/*
+ * FUNCTION: PKIX_PL_Cert_CreateFromCERTCertificate
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_CreateFromCERTCertificate(
+ const CERTCertificate *nssCert,
+ PKIX_PL_Cert **pCert,
+ void *plContext)
+{
+ void *buf = NULL;
+ PKIX_UInt32 len;
+ PKIX_PL_ByteArray *byteArray = NULL;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_CreateWithNssCert");
+ PKIX_NULLCHECK_TWO(pCert, nssCert);
+
+ buf = (void*)nssCert->derCert.data;
+ len = nssCert->derCert.len;
+
+ PKIX_CHECK(
+ PKIX_PL_ByteArray_Create(buf, len, &byteArray, plContext),
+ PKIX_BYTEARRAYCREATEFAILED);
+
+ PKIX_CHECK(
+ PKIX_PL_Cert_Create(byteArray, pCert, plContext),
+ PKIX_CERTCREATEWITHNSSCERTFAILED);
+
+#ifdef PKIX_UNDEF
+ /* will be tested and used as a patch for bug 391612 */
+ nssCert = CERT_DupCertificate(nssInCert);
+
+ PKIX_CHECK(pkix_pl_Cert_CreateWithNSSCert
+ (nssCert, &cert, plContext),
+ PKIX_CERTCREATEWITHNSSCERTFAILED);
+#endif /* PKIX_UNDEF */
+
+cleanup:
+
+#ifdef PKIX_UNDEF
+ if (nssCert && PKIX_ERROR_RECEIVED){
+ PKIX_CERT_DEBUG("\t\tCalling CERT_DestroyCertificate).\n");
+ CERT_DestroyCertificate(nssCert);
+ nssCert = NULL;
+ }
+#endif /* PKIX_UNDEF */
+
+ PKIX_DECREF(byteArray);
+ PKIX_RETURN(CERT);
+}
+
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetVersion (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetVersion(
+ PKIX_PL_Cert *cert,
+ PKIX_UInt32 *pVersion,
+ void *plContext)
+{
+ CERTCertificate *nssCert = NULL;
+ PKIX_UInt32 myVersion = 0; /* v1 */
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetVersion");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pVersion);
+
+ nssCert = cert->nssCert;
+ if (nssCert->version.len != 0) {
+ myVersion = *(nssCert->version.data);
+ }
+
+ if (myVersion > 2){
+ PKIX_ERROR(PKIX_VERSIONVALUEMUSTBEV1V2ORV3);
+ }
+
+ *pVersion = myVersion;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetSerialNumber (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetSerialNumber(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_BigInt **pSerialNumber,
+ void *plContext)
+{
+ CERTCertificate *nssCert = NULL;
+ SECItem serialNumItem;
+ PKIX_PL_BigInt *serialNumber = NULL;
+ char *bytes = NULL;
+ PKIX_UInt32 length;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSerialNumber");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSerialNumber);
+
+ if (cert->serialNumber == NULL){
+
+ PKIX_OBJECT_LOCK(cert);
+
+ if (cert->serialNumber == NULL){
+
+ nssCert = cert->nssCert;
+ serialNumItem = nssCert->serialNumber;
+
+ length = serialNumItem.len;
+ bytes = (char *)serialNumItem.data;
+
+ PKIX_CHECK(pkix_pl_BigInt_CreateWithBytes
+ (bytes, length, &serialNumber, plContext),
+ PKIX_BIGINTCREATEWITHBYTESFAILED);
+
+ /* save a cached copy in case it is asked for again */
+ cert->serialNumber = serialNumber;
+ }
+
+ PKIX_OBJECT_UNLOCK(cert);
+ }
+
+ PKIX_INCREF(cert->serialNumber);
+ *pSerialNumber = cert->serialNumber;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetSubject (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetSubject(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_X500Name **pCertSubject,
+ void *plContext)
+{
+ PKIX_PL_X500Name *pkixSubject = NULL;
+ CERTName *subjName = NULL;
+ SECItem *derSubjName = NULL;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubject");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pCertSubject);
+
+ /* if we don't have a cached copy from before, we create one */
+ if (cert->subject == NULL){
+
+ PKIX_OBJECT_LOCK(cert);
+
+ if (cert->subject == NULL){
+
+ subjName = &cert->nssCert->subject;
+ derSubjName = &cert->nssCert->derSubject;
+
+ /* if there is no subject name */
+ if (derSubjName->data == NULL) {
+
+ pkixSubject = NULL;
+
+ } else {
+ PKIX_CHECK(PKIX_PL_X500Name_CreateFromCERTName
+ (derSubjName, subjName, &pkixSubject,
+ plContext),
+ PKIX_X500NAMECREATEFROMCERTNAMEFAILED);
+
+ }
+ /* save a cached copy in case it is asked for again */
+ cert->subject = pkixSubject;
+ }
+
+ PKIX_OBJECT_UNLOCK(cert);
+ }
+
+ PKIX_INCREF(cert->subject);
+ *pCertSubject = cert->subject;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetIssuer (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetIssuer(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_X500Name **pCertIssuer,
+ void *plContext)
+{
+ PKIX_PL_X500Name *pkixIssuer = NULL;
+ SECItem *derIssuerName = NULL;
+ CERTName *issuerName = NULL;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetIssuer");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pCertIssuer);
+
+ /* if we don't have a cached copy from before, we create one */
+ if (cert->issuer == NULL){
+
+ PKIX_OBJECT_LOCK(cert);
+
+ if (cert->issuer == NULL){
+
+ issuerName = &cert->nssCert->issuer;
+ derIssuerName = &cert->nssCert->derIssuer;
+
+ /* if there is no subject name */
+ PKIX_CHECK(PKIX_PL_X500Name_CreateFromCERTName
+ (derIssuerName, issuerName,
+ &pkixIssuer, plContext),
+ PKIX_X500NAMECREATEFROMCERTNAMEFAILED);
+
+ /* save a cached copy in case it is asked for again */
+ cert->issuer = pkixIssuer;
+ }
+
+ PKIX_OBJECT_UNLOCK(cert);
+ }
+
+ PKIX_INCREF(cert->issuer);
+ *pCertIssuer = cert->issuer;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetSubjectAltNames (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetSubjectAltNames(
+ PKIX_PL_Cert *cert,
+ PKIX_List **pSubjectAltNames, /* list of PKIX_PL_GeneralName */
+ void *plContext)
+{
+ PKIX_PL_GeneralName *pkixAltName = NULL;
+ PKIX_List *altNamesList = NULL;
+
+ CERTGeneralName *nssOriginalAltName = NULL;
+ CERTGeneralName *nssTempAltName = NULL;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubjectAltNames");
+ PKIX_NULLCHECK_TWO(cert, pSubjectAltNames);
+
+ /* if we don't have a cached copy from before, we create one */
+ if ((cert->subjAltNames == NULL) && (!cert->subjAltNamesAbsent)){
+
+ PKIX_OBJECT_LOCK(cert);
+
+ if ((cert->subjAltNames == NULL) &&
+ (!cert->subjAltNamesAbsent)){
+
+ PKIX_CHECK(pkix_pl_Cert_GetNssSubjectAltNames
+ (cert,
+ PKIX_TRUE,
+ &nssOriginalAltName,
+ plContext),
+ PKIX_CERTGETNSSSUBJECTALTNAMESFAILED);
+
+ if (nssOriginalAltName == NULL) {
+ cert->subjAltNamesAbsent = PKIX_TRUE;
+ pSubjectAltNames = NULL;
+ goto cleanup;
+ }
+
+ nssTempAltName = nssOriginalAltName;
+
+ PKIX_CHECK(PKIX_List_Create(&altNamesList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ do {
+ PKIX_CHECK(pkix_pl_GeneralName_Create
+ (nssTempAltName, &pkixAltName, plContext),
+ PKIX_GENERALNAMECREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (altNamesList,
+ (PKIX_PL_Object *)pkixAltName,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(pkixAltName);
+
+ PKIX_CERT_DEBUG
+ ("\t\tCalling CERT_GetNextGeneralName).\n");
+ nssTempAltName = CERT_GetNextGeneralName
+ (nssTempAltName);
+
+ } while (nssTempAltName != nssOriginalAltName);
+
+ /* save a cached copy in case it is asked for again */
+ cert->subjAltNames = altNamesList;
+ PKIX_CHECK(PKIX_List_SetImmutable
+ (cert->subjAltNames, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ }
+
+ PKIX_OBJECT_UNLOCK(cert);
+ }
+
+ PKIX_INCREF(cert->subjAltNames);
+
+ *pSubjectAltNames = cert->subjAltNames;
+
+cleanup:
+ PKIX_DECREF(pkixAltName);
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(altNamesList);
+ }
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetAllSubjectNames (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetAllSubjectNames(
+ PKIX_PL_Cert *cert,
+ PKIX_List **pAllSubjectNames, /* list of PKIX_PL_GeneralName */
+ void *plContext)
+{
+ CERTGeneralName *nssOriginalSubjectName = NULL;
+ CERTGeneralName *nssTempSubjectName = NULL;
+ PKIX_List *allSubjectNames = NULL;
+ PKIX_PL_GeneralName *pkixSubjectName = NULL;
+ PLArenaPool *arena = NULL;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetAllSubjectNames");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pAllSubjectNames);
+
+
+ if (cert->nssCert->subjectName == NULL){
+ /* if there is no subject DN, just get altnames */
+
+ PKIX_CHECK(pkix_pl_Cert_GetNssSubjectAltNames
+ (cert,
+ PKIX_FALSE, /* hasLock */
+ &nssOriginalSubjectName,
+ plContext),
+ PKIX_CERTGETNSSSUBJECTALTNAMESFAILED);
+
+ } else { /* get subject DN and altnames */
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ /* This NSS call returns both Subject and Subject Alt Names */
+ PKIX_CERT_DEBUG("\t\tCalling CERT_GetCertificateNames\n");
+ nssOriginalSubjectName =
+ CERT_GetCertificateNames(cert->nssCert, arena);
+ }
+
+ if (nssOriginalSubjectName == NULL) {
+ pAllSubjectNames = NULL;
+ goto cleanup;
+ }
+
+ nssTempSubjectName = nssOriginalSubjectName;
+
+ PKIX_CHECK(PKIX_List_Create(&allSubjectNames, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ do {
+ PKIX_CHECK(pkix_pl_GeneralName_Create
+ (nssTempSubjectName, &pkixSubjectName, plContext),
+ PKIX_GENERALNAMECREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (allSubjectNames,
+ (PKIX_PL_Object *)pkixSubjectName,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(pkixSubjectName);
+
+ PKIX_CERT_DEBUG
+ ("\t\tCalling CERT_GetNextGeneralName).\n");
+ nssTempSubjectName = CERT_GetNextGeneralName
+ (nssTempSubjectName);
+ } while (nssTempSubjectName != nssOriginalSubjectName);
+
+ *pAllSubjectNames = allSubjectNames;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(allSubjectNames);
+ }
+
+ if (arena){
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ PKIX_DECREF(pkixSubjectName);
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetSubjectPublicKeyAlgId
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetSubjectPublicKeyAlgId(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_OID **pSubjKeyAlgId,
+ void *plContext)
+{
+ PKIX_PL_OID *pubKeyAlgId = NULL;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubjectPublicKeyAlgId");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSubjKeyAlgId);
+
+ /* if we don't have a cached copy from before, we create one */
+ if (cert->publicKeyAlgId == NULL){
+ PKIX_OBJECT_LOCK(cert);
+ if (cert->publicKeyAlgId == NULL){
+ CERTCertificate *nssCert = cert->nssCert;
+ SECAlgorithmID *algorithm;
+ SECItem *algBytes;
+
+ algorithm = &nssCert->subjectPublicKeyInfo.algorithm;
+ algBytes = &algorithm->algorithm;
+ if (!algBytes->data || !algBytes->len) {
+ PKIX_ERROR_FATAL(PKIX_ALGORITHMBYTESLENGTH0);
+ }
+ PKIX_CHECK(PKIX_PL_OID_CreateBySECItem
+ (algBytes, &pubKeyAlgId, plContext),
+ PKIX_OIDCREATEFAILED);
+
+ /* save a cached copy in case it is asked for again */
+ cert->publicKeyAlgId = pubKeyAlgId;
+ pubKeyAlgId = NULL;
+ }
+ PKIX_OBJECT_UNLOCK(cert);
+ }
+
+ PKIX_INCREF(cert->publicKeyAlgId);
+ *pSubjKeyAlgId = cert->publicKeyAlgId;
+
+cleanup:
+ PKIX_DECREF(pubKeyAlgId);
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetSubjectPublicKey (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetSubjectPublicKey(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_PublicKey **pPublicKey,
+ void *plContext)
+{
+ PKIX_PL_PublicKey *pkixPubKey = NULL;
+ SECStatus rv;
+
+ CERTSubjectPublicKeyInfo *from = NULL;
+ CERTSubjectPublicKeyInfo *to = NULL;
+ SECItem *fromItem = NULL;
+ SECItem *toItem = NULL;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubjectPublicKey");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pPublicKey);
+
+ /* if we don't have a cached copy from before, we create one */
+ if (cert->publicKey == NULL){
+
+ PKIX_OBJECT_LOCK(cert);
+
+ if (cert->publicKey == NULL){
+
+ /* create a PKIX_PL_PublicKey object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_PUBLICKEY_TYPE,
+ sizeof (PKIX_PL_PublicKey),
+ (PKIX_PL_Object **)&pkixPubKey,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ /* initialize fields */
+ pkixPubKey->nssSPKI = NULL;
+
+ /* populate the SPKI field */
+ PKIX_CHECK(PKIX_PL_Malloc
+ (sizeof (CERTSubjectPublicKeyInfo),
+ (void **)&pkixPubKey->nssSPKI,
+ plContext),
+ PKIX_MALLOCFAILED);
+
+ to = pkixPubKey->nssSPKI;
+ from = &cert->nssCert->subjectPublicKeyInfo;
+
+ PKIX_NULLCHECK_TWO(to, from);
+
+ PKIX_CERT_DEBUG
+ ("\t\tCalling SECOID_CopyAlgorithmID).\n");
+ rv = SECOID_CopyAlgorithmID
+ (NULL, &to->algorithm, &from->algorithm);
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_SECOIDCOPYALGORITHMIDFAILED);
+ }
+
+ /*
+ * NSS stores the length of subjectPublicKey in bits.
+ * Therefore, we use that length converted to bytes
+ * using ((length+7)>>3) before calling PORT_Memcpy
+ * in order to avoid "read from uninitialized memory"
+ * errors.
+ */
+
+ toItem = &to->subjectPublicKey;
+ fromItem = &from->subjectPublicKey;
+
+ PKIX_NULLCHECK_TWO(toItem, fromItem);
+
+ toItem->type = fromItem->type;
+
+ toItem->data =
+ (unsigned char*) PORT_ZAlloc(fromItem->len);
+ if (!toItem->data){
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ (void) PORT_Memcpy(toItem->data,
+ fromItem->data,
+ (fromItem->len + 7)>>3);
+ toItem->len = fromItem->len;
+
+ /* save a cached copy in case it is asked for again */
+ cert->publicKey = pkixPubKey;
+ }
+
+ PKIX_OBJECT_UNLOCK(cert);
+ }
+
+ PKIX_INCREF(cert->publicKey);
+ *pPublicKey = cert->publicKey;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED && pkixPubKey){
+ PKIX_DECREF(pkixPubKey);
+ cert->publicKey = NULL;
+ }
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetCriticalExtensionOIDs
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetCriticalExtensionOIDs(
+ PKIX_PL_Cert *cert,
+ PKIX_List **pList, /* list of PKIX_PL_OID */
+ void *plContext)
+{
+ PKIX_List *oidsList = NULL;
+ CERTCertExtension **extensions = NULL;
+ CERTCertificate *nssCert = NULL;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetCriticalExtensionOIDs");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pList);
+
+ /* if we don't have a cached copy from before, we create one */
+ if (cert->critExtOids == NULL) {
+
+ PKIX_OBJECT_LOCK(cert);
+
+ if (cert->critExtOids == NULL) {
+
+ nssCert = cert->nssCert;
+
+ /*
+ * ASN.1 for Extension
+ *
+ * Extension ::= SEQUENCE {
+ * extnID OBJECT IDENTIFIER,
+ * critical BOOLEAN DEFAULT FALSE,
+ * extnValue OCTET STRING }
+ *
+ */
+
+ extensions = nssCert->extensions;
+
+ PKIX_CHECK(pkix_pl_OID_GetCriticalExtensionOIDs
+ (extensions, &oidsList, plContext),
+ PKIX_GETCRITICALEXTENSIONOIDSFAILED);
+
+ /* save a cached copy in case it is asked for again */
+ cert->critExtOids = oidsList;
+ }
+
+ PKIX_OBJECT_UNLOCK(cert);
+ }
+
+ /* We should return a copy of the List since this list changes */
+ PKIX_DUPLICATE(cert->critExtOids, pList, plContext,
+ PKIX_OBJECTDUPLICATELISTFAILED);
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetAuthorityKeyIdentifier
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetAuthorityKeyIdentifier(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_ByteArray **pAuthKeyId,
+ void *plContext)
+{
+ PKIX_PL_ByteArray *authKeyId = NULL;
+ CERTCertificate *nssCert = NULL;
+ CERTAuthKeyID *authKeyIdExtension = NULL;
+ PLArenaPool *arena = NULL;
+ SECItem retItem;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetAuthorityKeyIdentifier");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pAuthKeyId);
+
+ /* if we don't have a cached copy from before, we create one */
+ if ((cert->authKeyId == NULL) && (!cert->authKeyIdAbsent)){
+
+ PKIX_OBJECT_LOCK(cert);
+
+ if ((cert->authKeyId == NULL) && (!cert->authKeyIdAbsent)){
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ nssCert = cert->nssCert;
+
+ authKeyIdExtension =
+ CERT_FindAuthKeyIDExten(arena, nssCert);
+ if (authKeyIdExtension == NULL){
+ cert->authKeyIdAbsent = PKIX_TRUE;
+ *pAuthKeyId = NULL;
+ goto cleanup;
+ }
+
+ retItem = authKeyIdExtension->keyID;
+
+ if (retItem.len == 0){
+ cert->authKeyIdAbsent = PKIX_TRUE;
+ *pAuthKeyId = NULL;
+ goto cleanup;
+ }
+
+ PKIX_CHECK(PKIX_PL_ByteArray_Create
+ (retItem.data,
+ retItem.len,
+ &authKeyId,
+ plContext),
+ PKIX_BYTEARRAYCREATEFAILED);
+
+ /* save a cached copy in case it is asked for again */
+ cert->authKeyId = authKeyId;
+ }
+
+ PKIX_OBJECT_UNLOCK(cert);
+ }
+
+ PKIX_INCREF(cert->authKeyId);
+ *pAuthKeyId = cert->authKeyId;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ if (arena){
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetSubjectKeyIdentifier
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetSubjectKeyIdentifier(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_ByteArray **pSubjKeyId,
+ void *plContext)
+{
+ PKIX_PL_ByteArray *subjKeyId = NULL;
+ CERTCertificate *nssCert = NULL;
+ SECItem *retItem = NULL;
+ SECStatus status;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubjectKeyIdentifier");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSubjKeyId);
+
+ /* if we don't have a cached copy from before, we create one */
+ if ((cert->subjKeyId == NULL) && (!cert->subjKeyIdAbsent)){
+
+ PKIX_OBJECT_LOCK(cert);
+
+ if ((cert->subjKeyId == NULL) && (!cert->subjKeyIdAbsent)){
+
+ retItem = SECITEM_AllocItem(NULL, NULL, 0);
+ if (retItem == NULL){
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ nssCert = cert->nssCert;
+
+ status = CERT_FindSubjectKeyIDExtension
+ (nssCert, retItem);
+ if (status != SECSuccess) {
+ cert->subjKeyIdAbsent = PKIX_TRUE;
+ *pSubjKeyId = NULL;
+ goto cleanup;
+ }
+
+ PKIX_CHECK(PKIX_PL_ByteArray_Create
+ (retItem->data,
+ retItem->len,
+ &subjKeyId,
+ plContext),
+ PKIX_BYTEARRAYCREATEFAILED);
+
+ /* save a cached copy in case it is asked for again */
+ cert->subjKeyId = subjKeyId;
+ }
+
+ PKIX_OBJECT_UNLOCK(cert);
+ }
+
+ PKIX_INCREF(cert->subjKeyId);
+ *pSubjKeyId = cert->subjKeyId;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ if (retItem){
+ SECITEM_FreeItem(retItem, PKIX_TRUE);
+ }
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetExtendedKeyUsage (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetExtendedKeyUsage(
+ PKIX_PL_Cert *cert,
+ PKIX_List **pKeyUsage, /* list of PKIX_PL_OID */
+ void *plContext)
+{
+ CERTOidSequence *extKeyUsage = NULL;
+ CERTCertificate *nssCert = NULL;
+ PKIX_PL_OID *pkixOID = NULL;
+ PKIX_List *oidsList = NULL;
+ SECItem **oids = NULL;
+ SECItem encodedExtKeyUsage;
+ SECStatus rv;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetExtendedKeyUsage");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pKeyUsage);
+
+ /* if we don't have a cached copy from before, we create one */
+ if ((cert->extKeyUsages == NULL) && (!cert->extKeyUsagesAbsent)){
+
+ PKIX_OBJECT_LOCK(cert);
+
+ if ((cert->extKeyUsages == NULL) &&
+ (!cert->extKeyUsagesAbsent)){
+
+ nssCert = cert->nssCert;
+
+ rv = CERT_FindCertExtension
+ (nssCert, SEC_OID_X509_EXT_KEY_USAGE,
+ &encodedExtKeyUsage);
+ if (rv != SECSuccess){
+ cert->extKeyUsagesAbsent = PKIX_TRUE;
+ *pKeyUsage = NULL;
+ goto cleanup;
+ }
+
+ extKeyUsage =
+ CERT_DecodeOidSequence(&encodedExtKeyUsage);
+ if (extKeyUsage == NULL){
+ PKIX_ERROR(PKIX_CERTDECODEOIDSEQUENCEFAILED);
+ }
+
+ PORT_Free(encodedExtKeyUsage.data);
+
+ oids = extKeyUsage->oids;
+
+ if (!oids){
+ /* no extended key usage extensions found */
+ cert->extKeyUsagesAbsent = PKIX_TRUE;
+ *pKeyUsage = NULL;
+ goto cleanup;
+ }
+
+ PKIX_CHECK(PKIX_List_Create(&oidsList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ while (*oids){
+ SECItem *oid = *oids++;
+
+ PKIX_CHECK(PKIX_PL_OID_CreateBySECItem
+ (oid, &pkixOID, plContext),
+ PKIX_OIDCREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (oidsList,
+ (PKIX_PL_Object *)pkixOID,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ PKIX_DECREF(pkixOID);
+ }
+
+ PKIX_CHECK(PKIX_List_SetImmutable
+ (oidsList, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ /* save a cached copy in case it is asked for again */
+ cert->extKeyUsages = oidsList;
+ oidsList = NULL;
+ }
+
+ PKIX_OBJECT_UNLOCK(cert);
+ }
+
+ PKIX_INCREF(cert->extKeyUsages);
+ *pKeyUsage = cert->extKeyUsages;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+
+ PKIX_DECREF(pkixOID);
+ PKIX_DECREF(oidsList);
+ CERT_DestroyOidSequence(extKeyUsage);
+
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetBasicConstraints
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetBasicConstraints(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_CertBasicConstraints **pBasicConstraints,
+ void *plContext)
+{
+ CERTCertificate *nssCert = NULL;
+ CERTBasicConstraints nssBasicConstraint;
+ SECStatus rv;
+ PKIX_PL_CertBasicConstraints *basic;
+ PKIX_Int32 pathLen = 0;
+ PKIX_Boolean isCA = PKIX_FALSE;
+ enum {
+ realBC, synthBC, absentBC
+ } constraintSource = absentBC;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetBasicConstraints");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pBasicConstraints);
+
+ /* if we don't have a cached copy from before, we create one */
+ if ((cert->certBasicConstraints == NULL) &&
+ (!cert->basicConstraintsAbsent)) {
+
+ PKIX_OBJECT_LOCK(cert);
+
+ if ((cert->certBasicConstraints == NULL) &&
+ (!cert->basicConstraintsAbsent)) {
+
+ nssCert = cert->nssCert;
+
+ PKIX_CERT_DEBUG(
+ "\t\tCalling Cert_FindBasicConstraintExten\n");
+ rv = CERT_FindBasicConstraintExten
+ (nssCert, &nssBasicConstraint);
+ if (rv == SECSuccess) {
+ constraintSource = realBC;
+ }
+
+ if (constraintSource == absentBC) {
+ /* can we deduce it's a CA and create a
+ synthetic constraint?
+ */
+ CERTCertTrust trust;
+ rv = CERT_GetCertTrust(nssCert, &trust);
+ if (rv == SECSuccess) {
+ int anyWantedFlag = CERTDB_TRUSTED_CA | CERTDB_VALID_CA;
+ if ((trust.sslFlags & anyWantedFlag)
+ || (trust.emailFlags & anyWantedFlag)
+ || (trust.objectSigningFlags & anyWantedFlag)) {
+
+ constraintSource = synthBC;
+ }
+ }
+ }
+
+ if (constraintSource == absentBC) {
+ cert->basicConstraintsAbsent = PKIX_TRUE;
+ *pBasicConstraints = NULL;
+ goto cleanup;
+ }
+ }
+
+ if (constraintSource == synthBC) {
+ isCA = PKIX_TRUE;
+ pathLen = PKIX_UNLIMITED_PATH_CONSTRAINT;
+ } else {
+ isCA = (nssBasicConstraint.isCA)?PKIX_TRUE:PKIX_FALSE;
+
+ /* The pathLen has meaning only for CAs */
+ if (isCA) {
+ if (CERT_UNLIMITED_PATH_CONSTRAINT ==
+ nssBasicConstraint.pathLenConstraint) {
+ pathLen = PKIX_UNLIMITED_PATH_CONSTRAINT;
+ } else {
+ pathLen = nssBasicConstraint.pathLenConstraint;
+ }
+ }
+ }
+
+ PKIX_CHECK(pkix_pl_CertBasicConstraints_Create
+ (isCA, pathLen, &basic, plContext),
+ PKIX_CERTBASICCONSTRAINTSCREATEFAILED);
+
+ /* save a cached copy in case it is asked for again */
+ cert->certBasicConstraints = basic;
+ }
+
+ PKIX_INCREF(cert->certBasicConstraints);
+ *pBasicConstraints = cert->certBasicConstraints;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetPolicyInformation
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetPolicyInformation(
+ PKIX_PL_Cert *cert,
+ PKIX_List **pPolicyInfo,
+ void *plContext)
+{
+ PKIX_List *policyList = NULL;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetPolicyInformation");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pPolicyInfo);
+
+ /* if we don't have a cached copy from before, we create one */
+ if ((cert->certPolicyInfos == NULL) &&
+ (!cert->policyInfoAbsent)) {
+
+ PKIX_OBJECT_LOCK(cert);
+
+ if ((cert->certPolicyInfos == NULL) &&
+ (!cert->policyInfoAbsent)) {
+
+ PKIX_CHECK(pkix_pl_Cert_DecodePolicyInfo
+ (cert->nssCert, &policyList, plContext),
+ PKIX_CERTDECODEPOLICYINFOFAILED);
+
+ if (!policyList) {
+ cert->policyInfoAbsent = PKIX_TRUE;
+ *pPolicyInfo = NULL;
+ goto cleanup;
+ }
+ }
+
+ PKIX_OBJECT_UNLOCK(cert);
+
+ /* save a cached copy in case it is asked for again */
+ cert->certPolicyInfos = policyList;
+ policyList = NULL;
+ }
+
+ PKIX_INCREF(cert->certPolicyInfos);
+ *pPolicyInfo = cert->certPolicyInfos;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+
+ PKIX_DECREF(policyList);
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetPolicyMappings (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetPolicyMappings(
+ PKIX_PL_Cert *cert,
+ PKIX_List **pPolicyMappings, /* list of PKIX_PL_CertPolicyMap */
+ void *plContext)
+{
+ PKIX_List *policyMappings = NULL; /* list of PKIX_PL_CertPolicyMap */
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetPolicyMappings");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pPolicyMappings);
+
+ /* if we don't have a cached copy from before, we create one */
+ if (!(cert->certPolicyMappings) && !(cert->policyMappingsAbsent)) {
+
+ PKIX_OBJECT_LOCK(cert);
+
+ if (!(cert->certPolicyMappings) &&
+ !(cert->policyMappingsAbsent)) {
+
+ PKIX_CHECK(pkix_pl_Cert_DecodePolicyMapping
+ (cert->nssCert, &policyMappings, plContext),
+ PKIX_CERTDECODEPOLICYMAPPINGFAILED);
+
+ if (!policyMappings) {
+ cert->policyMappingsAbsent = PKIX_TRUE;
+ *pPolicyMappings = NULL;
+ goto cleanup;
+ }
+ }
+
+ PKIX_OBJECT_UNLOCK(cert);
+
+ /* save a cached copy in case it is asked for again */
+ cert->certPolicyMappings = policyMappings;
+ policyMappings = NULL;
+ }
+
+ PKIX_INCREF(cert->certPolicyMappings);
+ *pPolicyMappings = cert->certPolicyMappings;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+
+ PKIX_DECREF(policyMappings);
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetRequireExplicitPolicy
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetRequireExplicitPolicy(
+ PKIX_PL_Cert *cert,
+ PKIX_Int32 *pSkipCerts,
+ void *plContext)
+{
+ PKIX_Int32 explicitPolicySkipCerts = 0;
+ PKIX_Int32 inhibitMappingSkipCerts = 0;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetRequireExplicitPolicy");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSkipCerts);
+
+ if (!(cert->policyConstraintsProcessed)) {
+ PKIX_OBJECT_LOCK(cert);
+
+ if (!(cert->policyConstraintsProcessed)) {
+
+ /*
+ * If we can't process it now, we probably will be
+ * unable to process it later. Set the default value.
+ */
+ cert->policyConstraintsProcessed = PKIX_TRUE;
+ cert->policyConstraintsExplicitPolicySkipCerts = -1;
+ cert->policyConstraintsInhibitMappingSkipCerts = -1;
+
+ PKIX_CHECK(pkix_pl_Cert_DecodePolicyConstraints
+ (cert->nssCert,
+ &explicitPolicySkipCerts,
+ &inhibitMappingSkipCerts,
+ plContext),
+ PKIX_CERTDECODEPOLICYCONSTRAINTSFAILED);
+
+ cert->policyConstraintsExplicitPolicySkipCerts =
+ explicitPolicySkipCerts;
+ cert->policyConstraintsInhibitMappingSkipCerts =
+ inhibitMappingSkipCerts;
+ }
+
+ PKIX_OBJECT_UNLOCK(cert);
+ }
+
+ *pSkipCerts = cert->policyConstraintsExplicitPolicySkipCerts;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetPolicyMappingInhibited
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetPolicyMappingInhibited(
+ PKIX_PL_Cert *cert,
+ PKIX_Int32 *pSkipCerts,
+ void *plContext)
+{
+ PKIX_Int32 explicitPolicySkipCerts = 0;
+ PKIX_Int32 inhibitMappingSkipCerts = 0;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetPolicyMappingInhibited");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSkipCerts);
+
+ if (!(cert->policyConstraintsProcessed)) {
+ PKIX_OBJECT_LOCK(cert);
+
+ if (!(cert->policyConstraintsProcessed)) {
+
+ /*
+ * If we can't process it now, we probably will be
+ * unable to process it later. Set the default value.
+ */
+ cert->policyConstraintsProcessed = PKIX_TRUE;
+ cert->policyConstraintsExplicitPolicySkipCerts = -1;
+ cert->policyConstraintsInhibitMappingSkipCerts = -1;
+
+ PKIX_CHECK(pkix_pl_Cert_DecodePolicyConstraints
+ (cert->nssCert,
+ &explicitPolicySkipCerts,
+ &inhibitMappingSkipCerts,
+ plContext),
+ PKIX_CERTDECODEPOLICYCONSTRAINTSFAILED);
+
+ cert->policyConstraintsExplicitPolicySkipCerts =
+ explicitPolicySkipCerts;
+ cert->policyConstraintsInhibitMappingSkipCerts =
+ inhibitMappingSkipCerts;
+ }
+
+ PKIX_OBJECT_UNLOCK(cert);
+ }
+
+ *pSkipCerts = cert->policyConstraintsInhibitMappingSkipCerts;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetInhibitAnyPolicy (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetInhibitAnyPolicy(
+ PKIX_PL_Cert *cert,
+ PKIX_Int32 *pSkipCerts,
+ void *plContext)
+{
+ PKIX_Int32 skipCerts = 0;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetInhibitAnyPolicy");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSkipCerts);
+
+ if (!(cert->inhibitAnyPolicyProcessed)) {
+
+ PKIX_OBJECT_LOCK(cert);
+
+ if (!(cert->inhibitAnyPolicyProcessed)) {
+
+ /*
+ * If we can't process it now, we probably will be
+ * unable to process it later. Set the default value.
+ */
+ cert->inhibitAnyPolicyProcessed = PKIX_TRUE;
+ cert->inhibitAnySkipCerts = -1;
+
+ PKIX_CHECK(pkix_pl_Cert_DecodeInhibitAnyPolicy
+ (cert->nssCert, &skipCerts, plContext),
+ PKIX_CERTDECODEINHIBITANYPOLICYFAILED);
+
+ cert->inhibitAnySkipCerts = skipCerts;
+ }
+
+ PKIX_OBJECT_UNLOCK(cert);
+ }
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ *pSkipCerts = cert->inhibitAnySkipCerts;
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_AreCertPoliciesCritical
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_AreCertPoliciesCritical(
+ PKIX_PL_Cert *cert,
+ PKIX_Boolean *pCritical,
+ void *plContext)
+{
+ PKIX_Boolean criticality = PKIX_FALSE;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_AreCertPoliciesCritical");
+ PKIX_NULLCHECK_TWO(cert, pCritical);
+
+ PKIX_CHECK(pkix_pl_Cert_IsExtensionCritical(
+ cert,
+ SEC_OID_X509_CERTIFICATE_POLICIES,
+ &criticality,
+ plContext),
+ PKIX_CERTISEXTENSIONCRITICALFAILED);
+
+ *pCritical = criticality;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_VerifySignature (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_VerifySignature(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_PublicKey *pubKey,
+ void *plContext)
+{
+ CERTCertificate *nssCert = NULL;
+ SECKEYPublicKey *nssPubKey = NULL;
+ CERTSignedData *tbsCert = NULL;
+ PKIX_PL_Cert *cachedCert = NULL;
+ PKIX_Error *verifySig = NULL;
+ PKIX_Error *cachedSig = NULL;
+ SECStatus status;
+ PKIX_Boolean certEqual = PKIX_FALSE;
+ PKIX_Boolean certInHash = PKIX_FALSE;
+ void* wincx = NULL;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_VerifySignature");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pubKey);
+
+ verifySig = PKIX_PL_HashTable_Lookup
+ (cachedCertSigTable,
+ (PKIX_PL_Object *) pubKey,
+ (PKIX_PL_Object **) &cachedCert,
+ plContext);
+
+ if (cachedCert != NULL && verifySig == NULL) {
+ /* Cached Signature Table lookup succeed */
+ PKIX_EQUALS(cert, cachedCert, &certEqual, plContext,
+ PKIX_OBJECTEQUALSFAILED);
+ if (certEqual == PKIX_TRUE) {
+ goto cleanup;
+ }
+ /* Different PubKey may hash to same value, skip add */
+ certInHash = PKIX_TRUE;
+ }
+
+ nssCert = cert->nssCert;
+ tbsCert = &nssCert->signatureWrap;
+
+ PKIX_CERT_DEBUG("\t\tCalling SECKEY_ExtractPublicKey).\n");
+ nssPubKey = SECKEY_ExtractPublicKey(pubKey->nssSPKI);
+ if (!nssPubKey){
+ PKIX_ERROR(PKIX_SECKEYEXTRACTPUBLICKEYFAILED);
+ }
+
+ PKIX_CERT_DEBUG("\t\tCalling CERT_VerifySignedDataWithPublicKey).\n");
+
+ PKIX_CHECK(pkix_pl_NssContext_GetWincx
+ ((PKIX_PL_NssContext *)plContext, &wincx),
+ PKIX_NSSCONTEXTGETWINCXFAILED);
+
+ status = CERT_VerifySignedDataWithPublicKey(tbsCert, nssPubKey, wincx);
+
+ if (status != SECSuccess) {
+ if (PORT_GetError() != SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED) {
+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+ }
+ PKIX_ERROR(PKIX_SIGNATUREDIDNOTVERIFYWITHTHEPUBLICKEY);
+ }
+
+ if (certInHash == PKIX_FALSE) {
+ cachedSig = PKIX_PL_HashTable_Add
+ (cachedCertSigTable,
+ (PKIX_PL_Object *) pubKey,
+ (PKIX_PL_Object *) cert,
+ plContext);
+
+ if (cachedSig != NULL) {
+ PKIX_DEBUG("PKIX_PL_HashTable_Add skipped: entry existed\n");
+ }
+ }
+
+cleanup:
+ if (nssPubKey){
+ PKIX_CERT_DEBUG("\t\tCalling SECKEY_DestroyPublicKey).\n");
+ SECKEY_DestroyPublicKey(nssPubKey);
+ }
+
+ PKIX_DECREF(cachedCert);
+ PKIX_DECREF(verifySig);
+ PKIX_DECREF(cachedSig);
+
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_CheckValidity (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_CheckValidity(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_Date *date,
+ void *plContext)
+{
+ SECCertTimeValidity val;
+ PRTime timeToCheck;
+ PKIX_Boolean allowOverride;
+ SECCertificateUsage requiredUsages;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_CheckValidity");
+ PKIX_NULLCHECK_ONE(cert);
+
+ /* if the caller supplies a date, we use it; else, use current time */
+ if (date != NULL){
+ PKIX_CHECK(pkix_pl_Date_GetPRTime
+ (date, &timeToCheck, plContext),
+ PKIX_DATEGETPRTIMEFAILED);
+ } else {
+ timeToCheck = PR_Now();
+ }
+
+ requiredUsages = ((PKIX_PL_NssContext*)plContext)->certificateUsage;
+ allowOverride =
+ (PRBool)((requiredUsages & certificateUsageSSLServer) ||
+ (requiredUsages & certificateUsageSSLServerWithStepUp));
+ val = CERT_CheckCertValidTimes(cert->nssCert, timeToCheck, allowOverride);
+ if (val != secCertTimeValid){
+ PKIX_ERROR(PKIX_CERTCHECKCERTVALIDTIMESFAILED);
+ }
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetValidityNotAfter (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetValidityNotAfter(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_Date **pDate,
+ void *plContext)
+{
+ PRTime prtime;
+ SECStatus rv = SECFailure;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetValidityNotAfter");
+ PKIX_NULLCHECK_TWO(cert, pDate);
+
+ PKIX_DATE_DEBUG("\t\tCalling DER_DecodeTimeChoice).\n");
+ rv = DER_DecodeTimeChoice(&prtime, &(cert->nssCert->validity.notAfter));
+ if (rv != SECSuccess){
+ PKIX_ERROR(PKIX_DERDECODETIMECHOICEFAILED);
+ }
+
+ PKIX_CHECK(pkix_pl_Date_CreateFromPRTime
+ (prtime, pDate, plContext),
+ PKIX_DATECREATEFROMPRTIMEFAILED);
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_VerifyCertAndKeyType (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_VerifyCertAndKeyType(
+ PKIX_PL_Cert *cert,
+ PKIX_Boolean isChainCert,
+ void *plContext)
+{
+ PKIX_PL_CertBasicConstraints *basicConstraints = NULL;
+ SECCertificateUsage certificateUsage;
+ SECCertUsage certUsage = 0;
+ unsigned int requiredKeyUsage;
+ unsigned int requiredCertType;
+ unsigned int certType;
+ SECStatus rv = SECSuccess;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_VerifyCertType");
+ PKIX_NULLCHECK_TWO(cert, plContext);
+
+ certificateUsage = ((PKIX_PL_NssContext*)plContext)->certificateUsage;
+
+ /* ensure we obtained a single usage bit only */
+ PORT_Assert(!(certificateUsage & (certificateUsage - 1)));
+
+ /* convert SECertificateUsage (bit mask) to SECCertUsage (enum) */
+ while (0 != (certificateUsage = certificateUsage >> 1)) { certUsage++; }
+
+ /* check key usage and netscape cert type */
+ cert_GetCertType(cert->nssCert);
+ certType = cert->nssCert->nsCertType;
+ if (isChainCert ||
+ (certUsage != certUsageVerifyCA && certUsage != certUsageAnyCA)) {
+ rv = CERT_KeyUsageAndTypeForCertUsage(certUsage, isChainCert,
+ &requiredKeyUsage,
+ &requiredCertType);
+ if (rv == SECFailure) {
+ PKIX_ERROR(PKIX_UNSUPPORTEDCERTUSAGE);
+ }
+ } else {
+ /* use this key usage and cert type for certUsageAnyCA and
+ * certUsageVerifyCA. */
+ requiredKeyUsage = KU_KEY_CERT_SIGN;
+ requiredCertType = NS_CERT_TYPE_CA;
+ }
+ if (CERT_CheckKeyUsage(cert->nssCert, requiredKeyUsage) != SECSuccess) {
+ PKIX_ERROR(PKIX_CERTCHECKKEYUSAGEFAILED);
+ }
+ if (!(certType & requiredCertType)) {
+ PKIX_ERROR(PKIX_CERTCHECKCERTTYPEFAILED);
+ }
+cleanup:
+ PKIX_DECREF(basicConstraints);
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_VerifyKeyUsage (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_VerifyKeyUsage(
+ PKIX_PL_Cert *cert,
+ PKIX_UInt32 keyUsage,
+ void *plContext)
+{
+ CERTCertificate *nssCert = NULL;
+ PKIX_UInt32 nssKeyUsage = 0;
+ SECStatus status;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_VerifyKeyUsage");
+ PKIX_NULLCHECK_TWO(cert, cert->nssCert);
+
+ nssCert = cert->nssCert;
+
+ /* if cert doesn't have keyUsage extension, all keyUsages are valid */
+ if (!nssCert->keyUsagePresent){
+ goto cleanup;
+ }
+
+ if (keyUsage & PKIX_DIGITAL_SIGNATURE){
+ nssKeyUsage = nssKeyUsage | KU_DIGITAL_SIGNATURE;
+ }
+
+ if (keyUsage & PKIX_NON_REPUDIATION){
+ nssKeyUsage = nssKeyUsage | KU_NON_REPUDIATION;
+ }
+
+ if (keyUsage & PKIX_KEY_ENCIPHERMENT){
+ nssKeyUsage = nssKeyUsage | KU_KEY_ENCIPHERMENT;
+ }
+
+ if (keyUsage & PKIX_DATA_ENCIPHERMENT){
+ nssKeyUsage = nssKeyUsage | KU_DATA_ENCIPHERMENT;
+ }
+
+ if (keyUsage & PKIX_KEY_AGREEMENT){
+ nssKeyUsage = nssKeyUsage | KU_KEY_AGREEMENT;
+ }
+
+ if (keyUsage & PKIX_KEY_CERT_SIGN){
+ nssKeyUsage = nssKeyUsage | KU_KEY_CERT_SIGN;
+ }
+
+ if (keyUsage & PKIX_CRL_SIGN){
+ nssKeyUsage = nssKeyUsage | KU_CRL_SIGN;
+ }
+
+ if (keyUsage & PKIX_ENCIPHER_ONLY){
+ nssKeyUsage = nssKeyUsage | 0x01;
+ }
+
+ if (keyUsage & PKIX_DECIPHER_ONLY){
+ /* XXX we should support this once it is fixed in NSS */
+ PKIX_ERROR(PKIX_DECIPHERONLYKEYUSAGENOTSUPPORTED);
+ }
+
+ status = CERT_CheckKeyUsage(nssCert, nssKeyUsage);
+ if (status != SECSuccess) {
+ PKIX_ERROR(PKIX_CERTCHECKKEYUSAGEFAILED);
+ }
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetNameConstraints
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetNameConstraints(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_CertNameConstraints **pNameConstraints,
+ void *plContext)
+{
+ PKIX_PL_CertNameConstraints *nameConstraints = NULL;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetNameConstraints");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pNameConstraints);
+
+ /* if we don't have a cached copy from before, we create one */
+ if (cert->nameConstraints == NULL && !cert->nameConstraintsAbsent) {
+
+ PKIX_OBJECT_LOCK(cert);
+
+ if (cert->nameConstraints == NULL &&
+ !cert->nameConstraintsAbsent) {
+
+ PKIX_CHECK(pkix_pl_CertNameConstraints_Create
+ (cert->nssCert, &nameConstraints, plContext),
+ PKIX_CERTNAMECONSTRAINTSCREATEFAILED);
+
+ if (nameConstraints == NULL) {
+ cert->nameConstraintsAbsent = PKIX_TRUE;
+ }
+
+ cert->nameConstraints = nameConstraints;
+ }
+
+ PKIX_OBJECT_UNLOCK(cert);
+
+ }
+
+ PKIX_INCREF(cert->nameConstraints);
+
+ *pNameConstraints = cert->nameConstraints;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_CheckNameConstraints
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_CheckNameConstraints(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_CertNameConstraints *nameConstraints,
+ PKIX_Boolean treatCommonNameAsDNSName,
+ void *plContext)
+{
+ PKIX_Boolean checkPass = PKIX_TRUE;
+ CERTGeneralName *nssSubjectNames = NULL;
+ PLArenaPool *arena = NULL;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_CheckNameConstraints");
+ PKIX_NULLCHECK_ONE(cert);
+
+ if (nameConstraints != NULL) {
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ /* This NSS call returns Subject Alt Names. If
+ * treatCommonNameAsDNSName is true, it also returns the
+ * Subject Common Name
+ */
+ PKIX_CERT_DEBUG
+ ("\t\tCalling CERT_GetConstrainedCertificateNames\n");
+ nssSubjectNames = CERT_GetConstrainedCertificateNames
+ (cert->nssCert, arena, treatCommonNameAsDNSName);
+
+ PKIX_CHECK(pkix_pl_CertNameConstraints_CheckNameSpaceNssNames
+ (nssSubjectNames,
+ nameConstraints,
+ &checkPass,
+ plContext),
+ PKIX_CERTNAMECONSTRAINTSCHECKNAMESPACENSSNAMESFAILED);
+
+ if (checkPass != PKIX_TRUE) {
+ PKIX_ERROR(PKIX_CERTFAILEDNAMECONSTRAINTSCHECKING);
+ }
+ }
+
+cleanup:
+ if (arena){
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_MergeNameConstraints
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_MergeNameConstraints(
+ PKIX_PL_CertNameConstraints *firstNC,
+ PKIX_PL_CertNameConstraints *secondNC,
+ PKIX_PL_CertNameConstraints **pResultNC,
+ void *plContext)
+{
+ PKIX_PL_CertNameConstraints *mergedNC = NULL;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_MergeNameConstraints");
+ PKIX_NULLCHECK_TWO(firstNC, pResultNC);
+
+ if (secondNC == NULL) {
+
+ PKIX_INCREF(firstNC);
+ *pResultNC = firstNC;
+
+ goto cleanup;
+ }
+
+ PKIX_CHECK(pkix_pl_CertNameConstraints_Merge
+ (firstNC, secondNC, &mergedNC, plContext),
+ PKIX_CERTNAMECONSTRAINTSMERGEFAILED);
+
+ *pResultNC = mergedNC;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * Find out the state of the NSS trust bits for the requested usage.
+ * Returns SECFailure if the cert is explicitly distrusted.
+ * Returns SECSuccess if the cert can be used to form a chain (normal case),
+ * or it is explicitly trusted. The trusted bool is set to true if it is
+ * explicitly trusted.
+ */
+static SECStatus
+pkix_pl_Cert_GetTrusted(void *plContext,
+ PKIX_PL_Cert *cert,
+ PKIX_Boolean *trusted,
+ PKIX_Boolean isCA)
+{
+ SECStatus rv;
+ CERTCertificate *nssCert = NULL;
+ SECCertUsage certUsage = 0;
+ SECCertificateUsage certificateUsage;
+ SECTrustType trustType;
+ unsigned int trustFlags;
+ unsigned int requiredFlags;
+ CERTCertTrust trust;
+
+ *trusted = PKIX_FALSE;
+
+ /* no key usage information */
+ if (plContext == NULL) {
+ return SECSuccess;
+ }
+
+ certificateUsage = ((PKIX_PL_NssContext*)plContext)->certificateUsage;
+
+ /* ensure we obtained a single usage bit only */
+ PORT_Assert(!(certificateUsage & (certificateUsage - 1)));
+
+ /* convert SECertificateUsage (bit mask) to SECCertUsage (enum) */
+ while (0 != (certificateUsage = certificateUsage >> 1)) { certUsage++; }
+
+ nssCert = cert->nssCert;
+
+ if (!isCA) {
+ PRBool prTrusted;
+ unsigned int failedFlags;
+ rv = cert_CheckLeafTrust(nssCert, certUsage,
+ &failedFlags, &prTrusted);
+ *trusted = (PKIX_Boolean) prTrusted;
+ return rv;
+ }
+ rv = CERT_TrustFlagsForCACertUsage(certUsage, &requiredFlags,
+ &trustType);
+ if (rv != SECSuccess) {
+ return SECSuccess;
+ }
+
+ rv = CERT_GetCertTrust(nssCert, &trust);
+ if (rv != SECSuccess) {
+ return SECSuccess;
+ }
+ trustFlags = SEC_GET_TRUST_FLAGS(&trust, trustType);
+ /* normally trustTypeNone usages accept any of the given trust bits
+ * being on as acceptable. If any are distrusted (and none are trusted),
+ * then we will also distrust the cert */
+ if ((trustFlags == 0) && (trustType == trustTypeNone)) {
+ trustFlags = trust.sslFlags | trust.emailFlags |
+ trust.objectSigningFlags;
+ }
+ if ((trustFlags & requiredFlags) == requiredFlags) {
+ *trusted = PKIX_TRUE;
+ return SECSuccess;
+ }
+ if ((trustFlags & CERTDB_TERMINAL_RECORD) &&
+ ((trustFlags & (CERTDB_VALID_CA|CERTDB_TRUSTED)) == 0)) {
+ return SECFailure;
+ }
+ return SECSuccess;
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_IsCertTrusted
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_IsCertTrusted(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_TrustAnchorMode trustAnchorMode,
+ PKIX_Boolean *pTrusted,
+ void *plContext)
+{
+ PKIX_CertStore_CheckTrustCallback trustCallback = NULL;
+ PKIX_Boolean trusted = PKIX_FALSE;
+ SECStatus rv = SECFailure;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_IsCertTrusted");
+ PKIX_NULLCHECK_TWO(cert, pTrusted);
+
+ /* Call GetTrusted first to see if we are going to distrust the
+ * certificate */
+ rv = pkix_pl_Cert_GetTrusted(plContext, cert, &trusted, PKIX_TRUE);
+ if (rv != SECSuccess) {
+ /* Failure means the cert is explicitly distrusted,
+ * let the next level know not to use it. */
+ *pTrusted = PKIX_FALSE;
+ PKIX_ERROR(PKIX_CERTISCERTTRUSTEDFAILED);
+ }
+
+ if (trustAnchorMode == PKIX_PL_TrustAnchorMode_Exclusive ||
+ (trustAnchorMode == PKIX_PL_TrustAnchorMode_Additive &&
+ cert->isUserTrustAnchor)) {
+ /* Use the trust anchor's |trusted| value */
+ *pTrusted = cert->isUserTrustAnchor;
+ goto cleanup;
+ }
+
+ /* no key usage information or store is not trusted */
+ if (plContext == NULL || cert->store == NULL) {
+ *pTrusted = PKIX_FALSE;
+ goto cleanup;
+ }
+
+ PKIX_CHECK(PKIX_CertStore_GetTrustCallback
+ (cert->store, &trustCallback, plContext),
+ PKIX_CERTSTOREGETTRUSTCALLBACKFAILED);
+
+ PKIX_CHECK_ONLY_FATAL(trustCallback
+ (cert->store, cert, &trusted, plContext),
+ PKIX_CHECKTRUSTCALLBACKFAILED);
+
+ /* allow trust store to override if we can trust the trust
+ * bits */
+ if (PKIX_ERROR_RECEIVED || (trusted == PKIX_FALSE)) {
+ *pTrusted = PKIX_FALSE;
+ goto cleanup;
+ }
+
+ *pTrusted = trusted;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_IsLeafCertTrusted
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_IsLeafCertTrusted(
+ PKIX_PL_Cert *cert,
+ PKIX_Boolean *pTrusted,
+ void *plContext)
+{
+ SECStatus rv;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_IsLeafCertTrusted");
+ PKIX_NULLCHECK_TWO(cert, pTrusted);
+
+ *pTrusted = PKIX_FALSE;
+
+ rv = pkix_pl_Cert_GetTrusted(plContext, cert, pTrusted, PKIX_FALSE);
+ if (rv != SECSuccess) {
+ /* Failure means the cert is explicitly distrusted,
+ * let the next level know not to use it. */
+ *pTrusted = PKIX_FALSE;
+ PKIX_ERROR(PKIX_CERTISCERTTRUSTEDFAILED);
+ }
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/* FUNCTION: PKIX_PL_Cert_SetAsTrustAnchor */
+PKIX_Error*
+PKIX_PL_Cert_SetAsTrustAnchor(PKIX_PL_Cert *cert,
+ void *plContext)
+{
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_SetAsTrustAnchor");
+ PKIX_NULLCHECK_ONE(cert);
+
+ cert->isUserTrustAnchor = PKIX_TRUE;
+
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetCacheFlag (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetCacheFlag(
+ PKIX_PL_Cert *cert,
+ PKIX_Boolean *pCacheFlag,
+ void *plContext)
+{
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetCacheFlag");
+ PKIX_NULLCHECK_TWO(cert, pCacheFlag);
+
+ *pCacheFlag = cert->cacheFlag;
+
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_SetCacheFlag (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_SetCacheFlag(
+ PKIX_PL_Cert *cert,
+ PKIX_Boolean cacheFlag,
+ void *plContext)
+{
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_SetCacheFlag");
+ PKIX_NULLCHECK_ONE(cert);
+
+ cert->cacheFlag = cacheFlag;
+
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetTrustCertStore (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetTrustCertStore(
+ PKIX_PL_Cert *cert,
+ PKIX_CertStore **pTrustCertStore,
+ void *plContext)
+{
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetTrustCertStore");
+ PKIX_NULLCHECK_TWO(cert, pTrustCertStore);
+
+ PKIX_INCREF(cert->store);
+ *pTrustCertStore = cert->store;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_SetTrustCertStore (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_SetTrustCertStore(
+ PKIX_PL_Cert *cert,
+ PKIX_CertStore *trustCertStore,
+ void *plContext)
+{
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_SetTrustCertStore");
+ PKIX_NULLCHECK_TWO(cert, trustCertStore);
+
+ PKIX_INCREF(trustCertStore);
+ cert->store = trustCertStore;
+
+cleanup:
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetAuthorityInfoAccess
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetAuthorityInfoAccess(
+ PKIX_PL_Cert *cert,
+ PKIX_List **pAiaList, /* of PKIX_PL_InfoAccess */
+ void *plContext)
+{
+ PKIX_List *aiaList = NULL; /* of PKIX_PL_InfoAccess */
+ SECItem *encodedAIA = NULL;
+ CERTAuthInfoAccess **aia = NULL;
+ PLArenaPool *arena = NULL;
+ SECStatus rv;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetAuthorityInfoAccess");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pAiaList);
+
+ /* if we don't have a cached copy from before, we create one */
+ if (cert->authorityInfoAccess == NULL) {
+
+ PKIX_OBJECT_LOCK(cert);
+
+ if (cert->authorityInfoAccess == NULL) {
+
+ PKIX_PL_NSSCALLRV(CERT, encodedAIA, SECITEM_AllocItem,
+ (NULL, NULL, 0));
+
+ if (encodedAIA == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ PKIX_PL_NSSCALLRV(CERT, rv, CERT_FindCertExtension,
+ (cert->nssCert,
+ SEC_OID_X509_AUTH_INFO_ACCESS,
+ encodedAIA));
+
+ if (rv == SECFailure) {
+ goto cleanup;
+ }
+
+ PKIX_PL_NSSCALLRV(CERT, arena, PORT_NewArena,
+ (DER_DEFAULT_CHUNKSIZE));
+
+ if (arena == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ PKIX_PL_NSSCALLRV
+ (CERT, aia, CERT_DecodeAuthInfoAccessExtension,
+ (arena, encodedAIA));
+
+ PKIX_CHECK(pkix_pl_InfoAccess_CreateList
+ (aia, &aiaList, plContext),
+ PKIX_INFOACCESSCREATELISTFAILED);
+
+ cert->authorityInfoAccess = aiaList;
+ }
+
+ PKIX_OBJECT_UNLOCK(cert);
+ }
+
+ PKIX_INCREF(cert->authorityInfoAccess);
+
+ *pAiaList = cert->authorityInfoAccess;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ if (arena != NULL) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ if (encodedAIA != NULL) {
+ SECITEM_FreeItem(encodedAIA, PR_TRUE);
+ }
+
+ PKIX_RETURN(CERT);
+}
+
+/* XXX Following defines belongs to NSS */
+static const unsigned char siaOIDString[] = {0x2b, 0x06, 0x01, 0x05, 0x05,
+ 0x07, 0x01, 0x0b};
+#define OI(x) { siDEROID, (unsigned char *)x, sizeof x }
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetSubjectInfoAccess
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetSubjectInfoAccess(
+ PKIX_PL_Cert *cert,
+ PKIX_List **pSiaList, /* of PKIX_PL_InfoAccess */
+ void *plContext)
+{
+ PKIX_List *siaList; /* of PKIX_PL_InfoAccess */
+ SECItem siaOID = OI(siaOIDString);
+ SECItem *encodedSubjInfoAccess = NULL;
+ CERTAuthInfoAccess **subjInfoAccess = NULL;
+ PLArenaPool *arena = NULL;
+ SECStatus rv;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetSubjectInfoAccess");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pSiaList);
+
+ /* XXX
+ * Codes to deal with SubjectInfoAccess OID should be moved to
+ * NSS soon. I implemented them here so we don't touch NSS
+ * source tree, from JP's suggestion.
+ */
+
+ /* if we don't have a cached copy from before, we create one */
+ if (cert->subjectInfoAccess == NULL) {
+
+ PKIX_OBJECT_LOCK(cert);
+
+ if (cert->subjectInfoAccess == NULL) {
+
+ encodedSubjInfoAccess = SECITEM_AllocItem(NULL, NULL, 0);
+ if (encodedSubjInfoAccess == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ PKIX_CERT_DEBUG
+ ("\t\tCalling CERT_FindCertExtensionByOID).\n");
+ rv = CERT_FindCertExtensionByOID
+ (cert->nssCert, &siaOID, encodedSubjInfoAccess);
+
+ if (rv == SECFailure) {
+ goto cleanup;
+ }
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ /* XXX
+ * Decode Subject Information Access -
+ * since its type is the same as Authority Information
+ * Access, reuse the call. NSS- change name to avoid
+ * confusion.
+ */
+ PKIX_CERT_DEBUG
+ ("\t\tCalling CERT_DecodeAuthInfoAccessExtension).\n");
+ subjInfoAccess = CERT_DecodeAuthInfoAccessExtension
+ (arena, encodedSubjInfoAccess);
+
+ PKIX_CHECK(pkix_pl_InfoAccess_CreateList
+ (subjInfoAccess, &siaList, plContext),
+ PKIX_INFOACCESSCREATELISTFAILED);
+
+ cert->subjectInfoAccess = siaList;
+
+ }
+
+ PKIX_OBJECT_UNLOCK(cert);
+ }
+
+ PKIX_INCREF(cert->subjectInfoAccess);
+ *pSiaList = cert->subjectInfoAccess;
+
+cleanup:
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ if (arena != NULL) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ if (encodedSubjInfoAccess != NULL) {
+ SECITEM_FreeItem(encodedSubjInfoAccess, PR_TRUE);
+ }
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetCrlDp
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetCrlDp(
+ PKIX_PL_Cert *cert,
+ PKIX_List **pDpList,
+ void *plContext)
+{
+ PKIX_UInt32 dpIndex = 0;
+ pkix_pl_CrlDp *dp = NULL;
+ CERTCrlDistributionPoints *dpoints = NULL;
+
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetCrlDp");
+ PKIX_NULLCHECK_THREE(cert, cert->nssCert, pDpList);
+
+ /* if we don't have a cached copy from before, we create one */
+ if (cert->crldpList == NULL) {
+ PKIX_OBJECT_LOCK(cert);
+ if (cert->crldpList != NULL) {
+ goto cleanup;
+ }
+ PKIX_CHECK(PKIX_List_Create(&cert->crldpList, plContext),
+ PKIX_LISTCREATEFAILED);
+ dpoints = CERT_FindCRLDistributionPoints(cert->nssCert);
+ if (!dpoints || !dpoints->distPoints) {
+ goto cleanup;
+ }
+ for (;dpoints->distPoints[dpIndex];dpIndex++) {
+ PKIX_CHECK(
+ pkix_pl_CrlDp_Create(dpoints->distPoints[dpIndex],
+ &cert->nssCert->issuer,
+ &dp, plContext),
+ PKIX_CRLDPCREATEFAILED);
+ /* Create crldp list in reverse order in attempt to get
+ * to the whole crl first. */
+ PKIX_CHECK(
+ PKIX_List_InsertItem(cert->crldpList, 0,
+ (PKIX_PL_Object*)dp,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ PKIX_DECREF(dp);
+ }
+ }
+cleanup:
+ PKIX_INCREF(cert->crldpList);
+ *pDpList = cert->crldpList;
+
+ PKIX_OBJECT_UNLOCK(lockedObject);
+ PKIX_DECREF(dp);
+
+ PKIX_RETURN(CERT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Cert_GetCERTCertificate
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Cert_GetCERTCertificate(
+ PKIX_PL_Cert *cert,
+ CERTCertificate **pnssCert,
+ void *plContext)
+{
+ PKIX_ENTER(CERT, "PKIX_PL_Cert_GetNssCert");
+ PKIX_NULLCHECK_TWO(cert, pnssCert);
+
+ *pnssCert = CERT_DupCertificate(cert->nssCert);
+
+ PKIX_RETURN(CERT);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.h
new file mode 100644
index 000000000..56fe64228
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_cert.h
@@ -0,0 +1,107 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_cert.h
+ *
+ * Certificate Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_CERT_H
+#define _PKIX_PL_CERT_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_CertStruct {
+ CERTCertificate *nssCert; /* Must be the first field. The
+ * cert_NSSCertFromPKIXCert function in
+ * lib/certhigh/certvfypkix.c depends on
+ * this. */
+ CERTGeneralName *nssSubjAltNames;
+ PLArenaPool *arenaNameConstraints;
+ PKIX_PL_X500Name *issuer;
+ PKIX_PL_X500Name *subject;
+ PKIX_List *subjAltNames;
+ PKIX_Boolean subjAltNamesAbsent;
+ PKIX_PL_OID *publicKeyAlgId;
+ PKIX_PL_PublicKey *publicKey;
+ PKIX_PL_BigInt *serialNumber;
+ PKIX_List *critExtOids;
+ PKIX_PL_ByteArray *subjKeyId;
+ PKIX_Boolean subjKeyIdAbsent;
+ PKIX_PL_ByteArray *authKeyId;
+ PKIX_Boolean authKeyIdAbsent;
+ PKIX_List *extKeyUsages;
+ PKIX_Boolean extKeyUsagesAbsent;
+ PKIX_PL_CertBasicConstraints *certBasicConstraints;
+ PKIX_Boolean basicConstraintsAbsent;
+ PKIX_List *certPolicyInfos;
+ PKIX_Boolean policyInfoAbsent;
+ PKIX_Boolean policyMappingsAbsent;
+ PKIX_List *certPolicyMappings; /* List of PKIX_PL_CertPolicyMap */
+ PKIX_Boolean policyConstraintsProcessed;
+ PKIX_Int32 policyConstraintsExplicitPolicySkipCerts;
+ PKIX_Int32 policyConstraintsInhibitMappingSkipCerts;
+ PKIX_Boolean inhibitAnyPolicyProcessed;
+ PKIX_Int32 inhibitAnySkipCerts;
+ PKIX_PL_CertNameConstraints *nameConstraints;
+ PKIX_Boolean nameConstraintsAbsent;
+ PKIX_Boolean cacheFlag;
+ PKIX_CertStore *store;
+ PKIX_List *authorityInfoAccess; /* list of PKIX_PL_InfoAccess */
+ PKIX_List *subjectInfoAccess; /* list of PKIX_PL_InfoAccess */
+ PKIX_Boolean isUserTrustAnchor;
+ PKIX_List *crldpList; /* list of CRL DPs based on der in nssCert arena.
+ * Destruction is needed for pkix object and
+ * not for undelying der as it is a part
+ * nssCert arena. */
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_pl_Cert_RegisterSelf(void *plContext);
+
+PKIX_Error *
+pkix_pl_Cert_CreateWithNSSCert(
+ CERTCertificate *nssCert,
+ PKIX_PL_Cert **pCert,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_Cert_CreateToList(
+ SECItem *derCertItem,
+ PKIX_List *certList,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_Cert_CheckSubjectAltNameConstraints(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_CertNameConstraints *nameConstraints,
+ PKIX_Boolean matchAll,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_Cert_ToString_Helper(
+ PKIX_PL_Cert *cert,
+ PKIX_Boolean partialString,
+ PKIX_PL_String **pString,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_Cert_CheckExtendedKeyUsage(
+ PKIX_PL_Cert *cert,
+ PKIX_UInt32 requiredExtendedKeyUsages,
+ PKIX_Boolean *pPass,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_CERT_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.c
new file mode 100644
index 000000000..a44ac6590
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.c
@@ -0,0 +1,371 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_certpolicyinfo.c
+ *
+ * CertPolicyInfo Type Functions
+ *
+ */
+
+#include "pkix_pl_certpolicyinfo.h"
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyInfo_Create
+ * DESCRIPTION:
+ *
+ * Creates a new CertPolicyInfo Object using the OID pointed to by "oid" and
+ * the List of CertPolicyQualifiers pointed to by "qualifiers", and stores it
+ * at "pObject". If a non-NULL list is provided, the caller is expected to
+ * have already set it to be immutable. The caller may provide an empty List,
+ * but a NULL List is preferable so a user does not need to call
+ * List_GetLength to get the number of qualifiers.
+ *
+ * PARAMETERS
+ * "oid"
+ * OID of the desired PolicyInfo ID; must be non-NULL
+ * "qualifiers"
+ * List of CertPolicyQualifiers; may be NULL or empty
+ * "pObject"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_CertPolicyInfo_Create(
+ PKIX_PL_OID *oid,
+ PKIX_List *qualifiers,
+ PKIX_PL_CertPolicyInfo **pObject,
+ void *plContext)
+{
+ PKIX_PL_CertPolicyInfo *policyInfo = NULL;
+
+ PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_Create");
+
+ PKIX_NULLCHECK_TWO(oid, pObject);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_CERTPOLICYINFO_TYPE,
+ sizeof (PKIX_PL_CertPolicyInfo),
+ (PKIX_PL_Object **)&policyInfo,
+ plContext),
+ PKIX_COULDNOTCREATECERTPOLICYINFOOBJECT);
+
+ PKIX_INCREF(oid);
+ policyInfo->cpID = oid;
+
+ PKIX_INCREF(qualifiers);
+ policyInfo->policyQualifiers = qualifiers;
+
+ *pObject = policyInfo;
+ policyInfo = NULL;
+
+cleanup:
+ PKIX_DECREF(policyInfo);
+
+ PKIX_RETURN(CERTPOLICYINFO);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyInfo_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertPolicyInfo_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_CertPolicyInfo *certPI = NULL;
+
+ PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_Destroy");
+
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYINFO_TYPE, plContext),
+ PKIX_OBJECTNOTCERTPOLICYINFO);
+
+ certPI = (PKIX_PL_CertPolicyInfo*)object;
+
+ PKIX_DECREF(certPI->cpID);
+ PKIX_DECREF(certPI->policyQualifiers);
+
+cleanup:
+
+ PKIX_RETURN(CERTPOLICYINFO);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyInfo_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertPolicyInfo_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_CertPolicyInfo *certPI = NULL;
+ PKIX_PL_String *oidString = NULL;
+ PKIX_PL_String *listString = NULL;
+ PKIX_PL_String *format = NULL;
+ PKIX_PL_String *outString = NULL;
+
+ PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_ToString");
+
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYINFO_TYPE, plContext),
+ PKIX_OBJECTNOTCERTPOLICYINFO);
+
+ certPI = (PKIX_PL_CertPolicyInfo *)object;
+
+ PKIX_NULLCHECK_ONE(certPI->cpID);
+
+ PKIX_TOSTRING
+ (certPI->cpID,
+ &oidString,
+ plContext,
+ PKIX_OIDTOSTRINGFAILED);
+
+ PKIX_TOSTRING
+ (certPI->policyQualifiers,
+ &listString,
+ plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ /* Put them together in the form OID[Qualifiers] */
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, "%s[%s]", 0, &format, plContext),
+ PKIX_ERRORINSTRINGCREATE);
+
+ PKIX_CHECK(PKIX_PL_Sprintf
+ (&outString, plContext, format, oidString, listString),
+ PKIX_ERRORINSPRINTF);
+
+ *pString = outString;
+
+cleanup:
+
+ PKIX_DECREF(oidString);
+ PKIX_DECREF(listString);
+ PKIX_DECREF(format);
+ PKIX_RETURN(CERTPOLICYINFO);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyInfo_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertPolicyInfo_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_CertPolicyInfo *certPI = NULL;
+ PKIX_UInt32 oidHash = 0;
+ PKIX_UInt32 listHash = 0;
+
+ PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_Hashcode");
+
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYINFO_TYPE, plContext),
+ PKIX_OBJECTNOTCERTPOLICYINFO);
+
+ certPI = (PKIX_PL_CertPolicyInfo *)object;
+
+ PKIX_NULLCHECK_ONE(certPI->cpID);
+
+ PKIX_HASHCODE
+ (certPI->cpID,
+ &oidHash,
+ plContext,
+ PKIX_ERRORINOIDHASHCODE);
+
+ PKIX_HASHCODE
+ (certPI->policyQualifiers,
+ &listHash,
+ plContext,
+ PKIX_ERRORINLISTHASHCODE);
+
+ *pHashcode = (31 * oidHash) + listHash;
+
+cleanup:
+
+ PKIX_RETURN(CERTPOLICYINFO);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyInfo_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertPolicyInfo_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_PL_CertPolicyInfo *firstCPI = NULL;
+ PKIX_PL_CertPolicyInfo *secondCPI = NULL;
+ PKIX_UInt32 secondType = 0;
+ PKIX_Boolean compare = PKIX_FALSE;
+
+ PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ /* test that firstObject is a CertPolicyInfo */
+ PKIX_CHECK(pkix_CheckType
+ (firstObject, PKIX_CERTPOLICYINFO_TYPE, plContext),
+ PKIX_FIRSTOBJECTNOTCERTPOLICYINFO);
+
+ /*
+ * Since we know firstObject is a CertPolicyInfo,
+ * if both references are identical, they must be equal
+ */
+ if (firstObject == secondObject){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondObject isn't a CertPolicyInfo, we
+ * don't throw an error. We simply return FALSE.
+ */
+ PKIX_CHECK(PKIX_PL_Object_GetType
+ (secondObject, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+ if (secondType != PKIX_CERTPOLICYINFO_TYPE) {
+ *pResult = PKIX_FALSE;
+ goto cleanup;
+ }
+
+ firstCPI = (PKIX_PL_CertPolicyInfo *)firstObject;
+ secondCPI = (PKIX_PL_CertPolicyInfo *)secondObject;
+
+ /*
+ * Compare the value of the OID components
+ */
+
+ PKIX_NULLCHECK_TWO(firstCPI->cpID, secondCPI->cpID);
+
+ PKIX_EQUALS
+ (firstCPI->cpID,
+ secondCPI->cpID,
+ &compare,
+ plContext,
+ PKIX_OIDEQUALSFAILED);
+
+ /*
+ * If the OIDs did not match, we don't need to
+ * compare the Lists. If the OIDs did match,
+ * the return value is the value of the
+ * List comparison.
+ */
+ if (compare) {
+ PKIX_EQUALS
+ (firstCPI->policyQualifiers,
+ secondCPI->policyQualifiers,
+ &compare,
+ plContext,
+ PKIX_LISTEQUALSFAILED);
+ }
+
+ *pResult = compare;
+
+cleanup:
+
+ PKIX_RETURN(CERTPOLICYINFO);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyInfo_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_CERTPOLICYINFO_TYPE and its related
+ * functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize,
+ * which should only be called once, it is acceptable that
+ * this function is not thread-safe.
+ */
+PKIX_Error *
+pkix_pl_CertPolicyInfo_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(CERTPOLICYINFO, "pkix_pl_CertPolicyInfo_RegisterSelf");
+
+ entry.description = "CertPolicyInfo";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_CertPolicyInfo);
+ entry.destructor = pkix_pl_CertPolicyInfo_Destroy;
+ entry.equalsFunction = pkix_pl_CertPolicyInfo_Equals;
+ entry.hashcodeFunction = pkix_pl_CertPolicyInfo_Hashcode;
+ entry.toStringFunction = pkix_pl_CertPolicyInfo_ToString;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_CERTPOLICYINFO_TYPE] = entry;
+
+ PKIX_RETURN(CERTPOLICYINFO);
+}
+
+/* --Public-CertPolicyInfo-Functions------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_CertPolicyInfo_GetPolicyId
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_CertPolicyInfo_GetPolicyId(
+ PKIX_PL_CertPolicyInfo *policyInfo,
+ PKIX_PL_OID **pPolicyId,
+ void *plContext)
+{
+ PKIX_ENTER(CERTPOLICYINFO, "PKIX_PL_CertPolicyInfo_GetPolicyId");
+
+ PKIX_NULLCHECK_TWO(policyInfo, pPolicyId);
+
+ PKIX_INCREF(policyInfo->cpID);
+
+ *pPolicyId = policyInfo->cpID;
+
+cleanup:
+ PKIX_RETURN(CERTPOLICYINFO);
+}
+
+/*
+ * FUNCTION: PKIX_PL_CertPolicyInfo_GetPolQualifiers
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_CertPolicyInfo_GetPolQualifiers(
+ PKIX_PL_CertPolicyInfo *policyInfo,
+ PKIX_List **pQuals,
+ void *plContext)
+{
+ PKIX_ENTER(CERTPOLICYINFO, "PKIX_PL_CertPolicyInfo_GetPolQualifiers");
+
+ PKIX_NULLCHECK_TWO(policyInfo, pQuals);
+
+ PKIX_INCREF(policyInfo->policyQualifiers);
+
+ /*
+ * This List is created in PKIX_PL_Cert_DecodePolicyInfo
+ * and is set immutable immediately after being created.
+ */
+ *pQuals = policyInfo->policyQualifiers;
+
+cleanup:
+ PKIX_RETURN(CERTPOLICYINFO);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.h
new file mode 100644
index 000000000..5c324e6cd
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyinfo.h
@@ -0,0 +1,50 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_certpolicyinfo.h
+ *
+ * PolicyInfo Type Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_POLICYINFO_H
+#define _PKIX_PL_POLICYINFO_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This structure reflects the contents of the policy info extension as
+ * described in Section 4.2.1.5 of RFC3280.
+ *
+ * PolicyInformation ::= SEQUENCE {
+ * policyIdentifier CertPolicyId,
+ * PolicyQualifiers SEQUENCE SIZE (1..MAX) OF
+ * PolicyQualifierInfo OPTIONAL }
+ *
+ */
+struct PKIX_PL_CertPolicyInfoStruct {
+ PKIX_PL_OID *cpID;
+ PKIX_List *policyQualifiers; /* LIST of PKIX_PL_CertPolicyQualifier */
+};
+
+PKIX_Error *
+pkix_pl_CertPolicyInfo_Create(
+ PKIX_PL_OID *oid,
+ PKIX_List *qualifiers,
+ PKIX_PL_CertPolicyInfo **pObject,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_CertPolicyInfo_RegisterSelf(
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_POLICYINFO_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.c
new file mode 100644
index 000000000..08b1ca9df
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.c
@@ -0,0 +1,386 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_certpolicymap.c
+ *
+ * CertPolicyMap Type Functions
+ *
+ */
+
+#include "pkix_pl_certpolicymap.h"
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyMap_Create
+ * DESCRIPTION:
+ *
+ * Creates a new CertPolicyMap Object pairing the OID given by
+ * "issuerDomainPolicy" with the OID given by "subjectDomainPolicy", and
+ * stores the result at "pCertPolicyMap".
+ *
+ * PARAMETERS
+ * "issuerDomainPolicy"
+ * Address of the OID of the IssuerDomainPolicy. Must be non-NULL.
+ * "subjectDomainPolicy"
+ * Address of the OID of the SubjectDomainPolicy. Must be non-NULL.
+ * "pCertPolicyMap"
+ * Address where CertPolicyMap pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CertPolicyMap Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_CertPolicyMap_Create(
+ PKIX_PL_OID *issuerDomainPolicy,
+ PKIX_PL_OID *subjectDomainPolicy,
+ PKIX_PL_CertPolicyMap **pCertPolicyMap,
+ void *plContext)
+{
+ PKIX_PL_CertPolicyMap *policyMap = NULL;
+
+ PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_Create");
+
+ PKIX_NULLCHECK_THREE
+ (issuerDomainPolicy, subjectDomainPolicy, pCertPolicyMap);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_CERTPOLICYMAP_TYPE,
+ sizeof (PKIX_PL_CertPolicyMap),
+ (PKIX_PL_Object **)&policyMap,
+ plContext),
+ PKIX_COULDNOTCREATECERTPOLICYMAPOBJECT);
+
+ PKIX_INCREF(issuerDomainPolicy);
+ policyMap->issuerDomainPolicy = issuerDomainPolicy;
+
+ PKIX_INCREF(subjectDomainPolicy);
+ policyMap->subjectDomainPolicy = subjectDomainPolicy;
+
+ *pCertPolicyMap = policyMap;
+ policyMap = NULL;
+
+cleanup:
+ PKIX_DECREF(policyMap);
+
+ PKIX_RETURN(CERTPOLICYMAP);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyMap_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertPolicyMap_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_CertPolicyMap *certMap = NULL;
+
+ PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_Destroy");
+
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYMAP_TYPE, plContext),
+ PKIX_OBJECTNOTCERTPOLICYMAP);
+
+ certMap = (PKIX_PL_CertPolicyMap*)object;
+
+ PKIX_DECREF(certMap->issuerDomainPolicy);
+ PKIX_DECREF(certMap->subjectDomainPolicy);
+
+cleanup:
+
+ PKIX_RETURN(CERTPOLICYMAP);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyMap_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertPolicyMap_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_CertPolicyMap *certMap = NULL;
+ PKIX_PL_String *format = NULL;
+ PKIX_PL_String *outString = NULL;
+ PKIX_PL_String *issuerString = NULL;
+ PKIX_PL_String *subjectString = NULL;
+
+ PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_ToString");
+
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYMAP_TYPE, plContext),
+ PKIX_OBJECTNOTCERTPOLICYMAP);
+
+ certMap = (PKIX_PL_CertPolicyMap *)object;
+
+ PKIX_TOSTRING
+ (certMap->issuerDomainPolicy,
+ &issuerString,
+ plContext,
+ PKIX_OBJECTTOSTRINGFAILED);
+
+ PKIX_TOSTRING
+ (certMap->subjectDomainPolicy,
+ &subjectString,
+ plContext,
+ PKIX_OBJECTTOSTRINGFAILED);
+
+ /* Put them together in the form issuerPolicy=>subjectPolicy */
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, "%s=>%s", 0, &format, plContext),
+ PKIX_ERRORINSTRINGCREATE);
+
+ PKIX_CHECK(PKIX_PL_Sprintf
+ (&outString, plContext, format, issuerString, subjectString),
+ PKIX_ERRORINSPRINTF);
+
+ *pString = outString;
+
+cleanup:
+ PKIX_DECREF(format);
+ PKIX_DECREF(issuerString);
+ PKIX_DECREF(subjectString);
+
+ PKIX_RETURN(CERTPOLICYMAP);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyMap_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertPolicyMap_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_UInt32 issuerHash = 0;
+ PKIX_UInt32 subjectHash = 0;
+ PKIX_PL_CertPolicyMap *certMap = NULL;
+
+ PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_Hashcode");
+
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CERTPOLICYMAP_TYPE, plContext),
+ PKIX_OBJECTNOTCERTPOLICYMAP);
+
+ certMap = (PKIX_PL_CertPolicyMap *)object;
+
+ PKIX_HASHCODE
+ (certMap->issuerDomainPolicy,
+ &issuerHash,
+ plContext,
+ PKIX_OBJECTHASHCODEFAILED);
+
+ PKIX_HASHCODE
+ (certMap->subjectDomainPolicy,
+ &subjectHash,
+ plContext,
+ PKIX_OBJECTHASHCODEFAILED);
+
+ *pHashcode = issuerHash*31 + subjectHash;
+
+cleanup:
+
+ PKIX_RETURN(CERTPOLICYMAP);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyMap_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertPolicyMap_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_PL_CertPolicyMap *firstCertMap = NULL;
+ PKIX_PL_CertPolicyMap *secondCertMap = NULL;
+ PKIX_UInt32 secondType = 0;
+ PKIX_Boolean compare = PKIX_FALSE;
+
+ PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ /* test that firstObject is a CertPolicyMap */
+ PKIX_CHECK(pkix_CheckType
+ (firstObject, PKIX_CERTPOLICYMAP_TYPE, plContext),
+ PKIX_FIRSTOBJECTNOTCERTPOLICYMAP);
+
+ /*
+ * Since we know firstObject is a CertPolicyMap,
+ * if both references are identical, they must be equal
+ */
+ if (firstObject == secondObject){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondObject isn't a CertPolicyMap, we
+ * don't throw an error. We simply return FALSE.
+ */
+ PKIX_CHECK(PKIX_PL_Object_GetType
+ (secondObject, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+ if (secondType != PKIX_CERTPOLICYMAP_TYPE) {
+ *pResult = PKIX_FALSE;
+ goto cleanup;
+ }
+
+ firstCertMap = (PKIX_PL_CertPolicyMap *)firstObject;
+ secondCertMap = (PKIX_PL_CertPolicyMap *)secondObject;
+
+ PKIX_EQUALS
+ (firstCertMap->issuerDomainPolicy,
+ secondCertMap->issuerDomainPolicy,
+ &compare,
+ plContext,
+ PKIX_OBJECTEQUALSFAILED);
+
+ if (compare) {
+ PKIX_EQUALS
+ (firstCertMap->subjectDomainPolicy,
+ secondCertMap->subjectDomainPolicy,
+ &compare,
+ plContext,
+ PKIX_OBJECTEQUALSFAILED);
+ }
+
+ *pResult = compare;
+
+cleanup:
+
+ PKIX_RETURN(CERTPOLICYMAP);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyMap_Duplicate
+ * (see comments for PKIX_PL_Duplicate_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertPolicyMap_Duplicate(
+ PKIX_PL_Object *object,
+ PKIX_PL_Object **pNewObject,
+ void *plContext)
+{
+ PKIX_PL_CertPolicyMap *original = NULL;
+ PKIX_PL_CertPolicyMap *copy = NULL;
+
+ PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_Duplicate");
+
+ PKIX_NULLCHECK_TWO(object, pNewObject);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_CERTPOLICYMAP_TYPE, plContext),
+ PKIX_OBJECTARGUMENTNOTPOLICYMAP);
+
+ original = (PKIX_PL_CertPolicyMap *)object;
+
+ PKIX_CHECK(pkix_pl_CertPolicyMap_Create
+ (original->issuerDomainPolicy,
+ original->subjectDomainPolicy,
+ &copy,
+ plContext),
+ PKIX_CERTPOLICYMAPCREATEFAILED);
+
+ *pNewObject = (PKIX_PL_Object *)copy;
+
+cleanup:
+
+ PKIX_RETURN(CERTPOLICYMAP);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyMap_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_CERTPOLICYMAP_TYPE and its related
+ * functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize,
+ * which should only be called once, it is acceptable that
+ * this function is not thread-safe.
+ */
+PKIX_Error *
+pkix_pl_CertPolicyMap_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(CERTPOLICYMAP, "pkix_pl_CertPolicyMap_RegisterSelf");
+
+ entry.description = "CertPolicyMap";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_CertPolicyMap);
+ entry.destructor = pkix_pl_CertPolicyMap_Destroy;
+ entry.equalsFunction = pkix_pl_CertPolicyMap_Equals;
+ entry.hashcodeFunction = pkix_pl_CertPolicyMap_Hashcode;
+ entry.toStringFunction = pkix_pl_CertPolicyMap_ToString;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_pl_CertPolicyMap_Duplicate;
+
+ systemClasses[PKIX_CERTPOLICYMAP_TYPE] = entry;
+
+ PKIX_RETURN(CERTPOLICYMAP);
+}
+
+/* --Public-CertPolicyMap-Functions------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_CertPolicyMap_GetIssuerDomainPolicy
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_CertPolicyMap_GetIssuerDomainPolicy(
+ PKIX_PL_CertPolicyMap *policyMapping,
+ PKIX_PL_OID **pIssuerDomainPolicy,
+ void *plContext)
+{
+ PKIX_ENTER
+ (CERTPOLICYMAP, "PKIX_PL_CertPolicyMap_GetIssuerDomainPolicy");
+
+ PKIX_NULLCHECK_TWO(policyMapping, pIssuerDomainPolicy);
+
+ PKIX_INCREF(policyMapping->issuerDomainPolicy);
+ *pIssuerDomainPolicy = policyMapping->issuerDomainPolicy;
+
+cleanup:
+ PKIX_RETURN(CERTPOLICYMAP);
+}
+
+/*
+ * FUNCTION: PKIX_PL_CertPolicyMap_GetSubjectDomainPolicy
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_CertPolicyMap_GetSubjectDomainPolicy(
+ PKIX_PL_CertPolicyMap *policyMapping,
+ PKIX_PL_OID **pSubjectDomainPolicy,
+ void *plContext)
+{
+ PKIX_ENTER
+ (CERTPOLICYMAP, "PKIX_PL_CertPolicyMap_GetSubjectDomainPolicy");
+
+ PKIX_NULLCHECK_TWO(policyMapping, pSubjectDomainPolicy);
+
+ PKIX_INCREF(policyMapping->subjectDomainPolicy);
+ *pSubjectDomainPolicy = policyMapping->subjectDomainPolicy;
+
+cleanup:
+ PKIX_RETURN(CERTPOLICYMAP);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.h
new file mode 100644
index 000000000..a03bce2c8
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicymap.h
@@ -0,0 +1,49 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_certpolicymap.h
+ *
+ * CertPolicyMap Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_CERTPOLICYMAP_H
+#define _PKIX_PL_CERTPOLICYMAP_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This structure reflects the contents of the policy mapping extension as
+ * described in Section 4.2.1.6 of RFC3280.
+ *
+ * PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
+ * issuerDomainPolicy CertPolicyId,
+ * subjectDomainPolicy CertPolicyId }
+ *
+ */
+struct PKIX_PL_CertPolicyMapStruct {
+ PKIX_PL_OID *issuerDomainPolicy;
+ PKIX_PL_OID *subjectDomainPolicy;
+};
+
+PKIX_Error *
+pkix_pl_CertPolicyMap_Create(
+ PKIX_PL_OID *issuerDomainPolicy,
+ PKIX_PL_OID *subjectDomainPolicy,
+ PKIX_PL_CertPolicyMap **pObject,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_CertPolicyMap_RegisterSelf(
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_CERTPOLICYMAP_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.c
new file mode 100644
index 000000000..b57623d26
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.c
@@ -0,0 +1,365 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_certpolicyqualifier.c
+ *
+ * CertPolicyQualifier Type Functions
+ *
+ */
+
+#include "pkix_pl_certpolicyqualifier.h"
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyQualifier_Create
+ * DESCRIPTION:
+ *
+ * Creates a CertPolicyQualifier object with the OID given by "oid"
+ * and the ByteArray given by "qualifier", and stores it at "pObject".
+ *
+ * PARAMETERS
+ * "oid"
+ * Address of OID of the desired policyQualifierId; must be non-NULL
+ * "qualifier"
+ * Address of ByteArray with the desired value of the qualifier;
+ * must be non-NULL
+ * "pObject"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_CertPolicyQualifier_Create(
+ PKIX_PL_OID *oid,
+ PKIX_PL_ByteArray *qualifier,
+ PKIX_PL_CertPolicyQualifier **pObject,
+ void *plContext)
+{
+ PKIX_PL_CertPolicyQualifier *qual = NULL;
+
+ PKIX_ENTER(CERTPOLICYQUALIFIER, "pkix_pl_CertPolicyQualifier_Create");
+
+ PKIX_NULLCHECK_THREE(oid, qualifier, pObject);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_CERTPOLICYQUALIFIER_TYPE,
+ sizeof (PKIX_PL_CertPolicyQualifier),
+ (PKIX_PL_Object **)&qual,
+ plContext),
+ PKIX_COULDNOTCREATECERTPOLICYQUALIFIEROBJECT);
+
+ PKIX_INCREF(oid);
+ qual->policyQualifierId = oid;
+
+ PKIX_INCREF(qualifier);
+ qual->qualifier = qualifier;
+
+ *pObject = qual;
+ qual = NULL;
+
+cleanup:
+ PKIX_DECREF(qual);
+
+ PKIX_RETURN(CERTPOLICYQUALIFIER);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyQualifier_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertPolicyQualifier_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_CertPolicyQualifier *certPQ = NULL;
+
+ PKIX_ENTER(CERTPOLICYQUALIFIER, "pkix_pl_CertPolicyQualifier_Destroy");
+
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_CERTPOLICYQUALIFIER_TYPE, plContext),
+ PKIX_OBJECTNOTCERTPOLICYQUALIFIER);
+
+ certPQ = (PKIX_PL_CertPolicyQualifier*)object;
+
+ PKIX_DECREF(certPQ->policyQualifierId);
+ PKIX_DECREF(certPQ->qualifier);
+
+cleanup:
+
+ PKIX_RETURN(CERTPOLICYQUALIFIER);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyQualifier_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertPolicyQualifier_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_CertPolicyQualifier *certPQ = NULL;
+ char *asciiFormat = "%s:%s";
+ PKIX_PL_String *formatString = NULL;
+ PKIX_PL_String *pqIDString = NULL;
+ PKIX_PL_String *pqValString = NULL;
+ PKIX_PL_String *outString = NULL;
+
+ PKIX_ENTER(CERTPOLICYQUALIFIER, "pkix_pl_CertPolicyQualifier_ToString");
+
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_CERTPOLICYQUALIFIER_TYPE, plContext),
+ PKIX_OBJECTNOTCERTPOLICYQUALIFIER);
+
+ certPQ = (PKIX_PL_CertPolicyQualifier *)object;
+
+ /*
+ * The policyQualifierId is required. If there is no qualifier,
+ * we should have a ByteArray of zero length.
+ */
+ PKIX_NULLCHECK_TWO(certPQ->policyQualifierId, certPQ->qualifier);
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, asciiFormat, 0, &formatString, plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ PKIX_TOSTRING(certPQ->policyQualifierId, &pqIDString, plContext,
+ PKIX_OIDTOSTRINGFAILED);
+
+ PKIX_CHECK(pkix_pl_ByteArray_ToHexString
+ (certPQ->qualifier, &pqValString, plContext),
+ PKIX_BYTEARRAYTOHEXSTRINGFAILED);
+
+ PKIX_CHECK(PKIX_PL_Sprintf
+ (&outString, plContext, formatString, pqIDString, pqValString),
+ PKIX_SPRINTFFAILED);
+
+ *pString = outString;
+
+cleanup:
+
+ PKIX_DECREF(formatString);
+ PKIX_DECREF(pqIDString);
+ PKIX_DECREF(pqValString);
+ PKIX_RETURN(CERTPOLICYQUALIFIER);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyQualifier_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertPolicyQualifier_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_CertPolicyQualifier *certPQ = NULL;
+ PKIX_UInt32 cpidHash = 0;
+ PKIX_UInt32 cpqHash = 0;
+
+ PKIX_ENTER(CERTPOLICYQUALIFIER, "pkix_pl_CertPolicyQualifier_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_CERTPOLICYQUALIFIER_TYPE, plContext),
+ PKIX_OBJECTNOTCERTPOLICYQUALIFIER);
+
+ certPQ = (PKIX_PL_CertPolicyQualifier *)object;
+
+ PKIX_NULLCHECK_TWO(certPQ->policyQualifierId, certPQ->qualifier);
+
+ PKIX_HASHCODE(certPQ->policyQualifierId, &cpidHash, plContext,
+ PKIX_ERRORINOIDHASHCODE);
+
+ PKIX_HASHCODE(certPQ->qualifier, &cpqHash, plContext,
+ PKIX_ERRORINBYTEARRAYHASHCODE);
+
+ *pHashcode = cpidHash*31 + cpqHash;
+
+cleanup:
+
+ PKIX_RETURN(CERTPOLICYQUALIFIER);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyQualifier_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertPolicyQualifier_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_PL_CertPolicyQualifier *firstCPQ = NULL;
+ PKIX_PL_CertPolicyQualifier *secondCPQ = NULL;
+ PKIX_UInt32 secondType = 0;
+ PKIX_Boolean compare = PKIX_FALSE;
+
+ PKIX_ENTER(CERTPOLICYQUALIFIER, "pkix_pl_CertPolicyQualifier_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ /* test that firstObject is a CertPolicyQualifier */
+ PKIX_CHECK(pkix_CheckType
+ (firstObject, PKIX_CERTPOLICYQUALIFIER_TYPE, plContext),
+ PKIX_FIRSTOBJECTNOTCERTPOLICYQUALIFIER);
+
+ /*
+ * Since we know firstObject is a CertPolicyQualifier,
+ * if both references are identical, they must be equal
+ */
+ if (firstObject == secondObject){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondObject isn't a CertPolicyQualifier, we
+ * don't throw an error. We simply return FALSE.
+ */
+ PKIX_CHECK(PKIX_PL_Object_GetType
+ (secondObject, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+ if (secondType != PKIX_CERTPOLICYQUALIFIER_TYPE) {
+ *pResult = PKIX_FALSE;
+ goto cleanup;
+ }
+
+ firstCPQ = (PKIX_PL_CertPolicyQualifier *)firstObject;
+ secondCPQ = (PKIX_PL_CertPolicyQualifier *)secondObject;
+
+ /*
+ * Compare the value of the OID components
+ */
+
+ PKIX_NULLCHECK_TWO
+ (firstCPQ->policyQualifierId, secondCPQ->policyQualifierId);
+
+ PKIX_EQUALS
+ (firstCPQ->policyQualifierId,
+ secondCPQ->policyQualifierId,
+ &compare,
+ plContext,
+ PKIX_OIDEQUALSFAILED);
+
+ /*
+ * If the OIDs did not match, we don't need to
+ * compare the ByteArrays. If the OIDs did match,
+ * the return value is the value of the
+ * ByteArray comparison.
+ */
+ if (compare) {
+ PKIX_NULLCHECK_TWO(firstCPQ->qualifier, secondCPQ->qualifier);
+
+ PKIX_EQUALS
+ (firstCPQ->qualifier,
+ secondCPQ->qualifier,
+ &compare,
+ plContext,
+ PKIX_BYTEARRAYEQUALSFAILED);
+ }
+
+ *pResult = compare;
+
+cleanup:
+
+ PKIX_RETURN(CERTPOLICYQUALIFIER);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertPolicyQualifier_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_CERTPOLICYQUALIFIER_TYPE and its related
+ * functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize,
+ * which should only be called once, it is acceptable that
+ * this function is not thread-safe.
+ */
+PKIX_Error *
+pkix_pl_CertPolicyQualifier_RegisterSelf(void *plContext)
+{
+
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(CERTPOLICYQUALIFIER,
+ "pkix_pl_CertPolicyQualifier_RegisterSelf");
+
+ entry.description = "CertPolicyQualifier";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_CertPolicyQualifier);
+ entry.destructor = pkix_pl_CertPolicyQualifier_Destroy;
+ entry.equalsFunction = pkix_pl_CertPolicyQualifier_Equals;
+ entry.hashcodeFunction = pkix_pl_CertPolicyQualifier_Hashcode;
+ entry.toStringFunction = pkix_pl_CertPolicyQualifier_ToString;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_CERTPOLICYQUALIFIER_TYPE] = entry;
+
+ PKIX_RETURN(CERTPOLICYQUALIFIER);
+}
+
+/* --Public-CertPolicyQualifier-Functions------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_PolicyQualifier_GetPolicyQualifierId
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_PolicyQualifier_GetPolicyQualifierId(
+ PKIX_PL_CertPolicyQualifier *policyQualifierInfo,
+ PKIX_PL_OID **pPolicyQualifierId,
+ void *plContext)
+{
+ PKIX_ENTER(CERTPOLICYQUALIFIER,
+ "PKIX_PL_PolicyQualifier_GetPolicyQualifierId");
+
+ PKIX_NULLCHECK_TWO(policyQualifierInfo, pPolicyQualifierId);
+
+ PKIX_INCREF(policyQualifierInfo->policyQualifierId);
+
+ *pPolicyQualifierId = policyQualifierInfo->policyQualifierId;
+
+cleanup:
+ PKIX_RETURN(CERTPOLICYQUALIFIER);
+}
+
+/*
+ * FUNCTION: PKIX_PL_PolicyQualifier_GetQualifier
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_PolicyQualifier_GetQualifier(
+ PKIX_PL_CertPolicyQualifier *policyQualifierInfo,
+ PKIX_PL_ByteArray **pQualifier,
+ void *plContext)
+{
+ PKIX_ENTER(CERTPOLICYQUALIFIER, "PKIX_PL_PolicyQualifier_GetQualifier");
+
+ PKIX_NULLCHECK_TWO(policyQualifierInfo, pQualifier);
+
+ PKIX_INCREF(policyQualifierInfo->qualifier);
+
+ *pQualifier = policyQualifierInfo->qualifier;
+
+cleanup:
+ PKIX_RETURN(CERTPOLICYQUALIFIER);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.h
new file mode 100644
index 000000000..4c6c8a21b
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_certpolicyqualifier.h
@@ -0,0 +1,52 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_certpolicyqualifier.h
+ *
+ * PolicyQualifier Type Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_POLICYQUALIFIER_H
+#define _PKIX_PL_POLICYQUALIFIER_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * This structure reflects the contents of the policy qualifier extension as
+ * described in Section 4.2.1.5 of RFC3280.
+ *
+ * PolicyQualifierInfo ::= SEQUENCE {
+ * policyQualifierId PolicyQualifierId,
+ * qualifier ANY DEFINED BY policyQualifierId }
+ *
+ * PolicyQualifierId ::=
+ * OBJECT IDENTIFIER (id-qt-cps | id-qt-unotice)
+ *
+ */
+struct PKIX_PL_CertPolicyQualifierStruct {
+ PKIX_PL_OID *policyQualifierId;
+ PKIX_PL_ByteArray *qualifier;
+};
+
+PKIX_Error *
+pkix_pl_CertPolicyQualifier_Create(
+ PKIX_PL_OID *oid,
+ PKIX_PL_ByteArray *qualifierArray,
+ PKIX_PL_CertPolicyQualifier **pObject,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_CertPolicyQualifier_RegisterSelf(
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_POLICYQUALIFIER_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.c
new file mode 100644
index 000000000..b83db357a
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.c
@@ -0,0 +1,1068 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_crl.c
+ *
+ * CRL Function Definitions
+ *
+ */
+
+#include "pkix_pl_crl.h"
+#include "certxutl.h"
+
+extern PKIX_PL_HashTable *cachedCrlSigTable;
+
+/* --Private-CRL-Functions------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_CRL_GetVersion
+ * DESCRIPTION:
+ *
+ * Retrieves the version of the CRL pointed to by "crl" and stores it at
+ * "pVersion". The version number will either be 0 or 1 (corresponding to
+ * v1 or v2, respectively).
+ *
+ * Version ::= INTEGER { v1(0), v2(1), v3(2) }
+ *
+ * PARAMETERS:
+ * "crl"
+ * Address of CRL whose version is to be stored. Must be non-NULL.
+ * "pVersion"
+ * Address where a version will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CRL Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CRL_GetVersion(
+ PKIX_PL_CRL *crl,
+ PKIX_UInt32 *pVersion,
+ void *plContext)
+{
+ PKIX_UInt32 myVersion;
+
+ PKIX_ENTER(CRL, "pkix_pl_CRL_GetVersion");
+ PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pVersion);
+
+ PKIX_NULLCHECK_ONE(crl->nssSignedCrl->crl.version.data);
+
+ myVersion = *(crl->nssSignedCrl->crl.version.data);
+
+ if (myVersion > 1) {
+ PKIX_ERROR(PKIX_VERSIONVALUEMUSTBEV1ORV2);
+ }
+
+ *pVersion = myVersion;
+
+cleanup:
+
+ PKIX_RETURN(CRL);
+}
+
+/*
+ * FUNCTION: PKIX_PL_CRL_GetCRLNumber (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_CRL_GetCRLNumber(
+ PKIX_PL_CRL *crl,
+ PKIX_PL_BigInt **pCrlNumber,
+ void *plContext)
+{
+ PKIX_PL_BigInt *crlNumber = NULL;
+ SECItem nssCrlNumber;
+ PLArenaPool *arena = NULL;
+ SECStatus status;
+ PKIX_UInt32 length = 0;
+ char *bytes = NULL;
+
+ PKIX_ENTER(CRL, "PKIX_PL_CRL_GetCRLNumber");
+ PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pCrlNumber);
+
+ /* Can call this function only with der been adopted. */
+ PORT_Assert(crl->adoptedDerCrl);
+
+ if (!crl->crlNumberAbsent && crl->crlNumber == NULL) {
+
+ PKIX_OBJECT_LOCK(crl);
+
+ if (!crl->crlNumberAbsent && crl->crlNumber == NULL) {
+
+ nssCrlNumber.type = 0;
+ nssCrlNumber.len = 0;
+ nssCrlNumber.data = NULL;
+
+ PKIX_CRL_DEBUG("\t\tCalling PORT_NewArena).\n");
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ PKIX_CRL_DEBUG("\t\tCalling CERT_FindCRLNumberExten\n");
+ status = CERT_FindCRLNumberExten
+ (arena, &crl->nssSignedCrl->crl, &nssCrlNumber);
+
+ if (status == SECSuccess) {
+ /* Get data in bytes then convert to bigint */
+ length = nssCrlNumber.len;
+ bytes = (char *)nssCrlNumber.data;
+
+ PKIX_CHECK(pkix_pl_BigInt_CreateWithBytes
+ (bytes, length, &crlNumber, plContext),
+ PKIX_BIGINTCREATEWITHBYTESFAILED);
+
+ /* arena release does the job
+ PKIX_CRL_DEBUG("\t\tCalling SECITEM_FreeItem\n");
+ SECITEM_FreeItem(&nssCrlNumber, PKIX_FALSE);
+ */
+ crl->crlNumber = crlNumber;
+
+ } else {
+
+ crl->crlNumberAbsent = PKIX_TRUE;
+ }
+ }
+
+ PKIX_OBJECT_UNLOCK(crl);
+
+ }
+
+ PKIX_INCREF(crl->crlNumber);
+
+ *pCrlNumber = crl->crlNumber;
+
+cleanup:
+
+ if (arena){
+ PKIX_CRL_DEBUG("\t\tCalling PORT_FreeArena).\n");
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ PKIX_RETURN(CRL);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRL_GetSignatureAlgId
+ *
+ * DESCRIPTION:
+ * Retrieves a pointer to the OID that represents the signature algorithm of
+ * the CRL pointed to by "crl" and stores it at "pSignatureAlgId".
+ *
+ * AlgorithmIdentifier ::= SEQUENCE {
+ * algorithm OBJECT IDENTIFIER,
+ * parameters ANY DEFINED BY algorithm OPTIONAL }
+ *
+ * PARAMETERS:
+ * "crl"
+ * Address of CRL whose signature algorithm OID is to be stored.
+ * Must be non-NULL.
+ * "pSignatureAlgId"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CRL Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CRL_GetSignatureAlgId(
+ PKIX_PL_CRL *crl,
+ PKIX_PL_OID **pSignatureAlgId,
+ void *plContext)
+{
+ PKIX_PL_OID *signatureAlgId = NULL;
+
+ PKIX_ENTER(CRL, "pkix_pl_CRL_GetSignatureAlgId");
+ PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pSignatureAlgId);
+
+ /* if we don't have a cached copy from before, we create one */
+ if (crl->signatureAlgId == NULL){
+ PKIX_OBJECT_LOCK(crl);
+ if (crl->signatureAlgId == NULL){
+ CERTCrl *nssCrl = &(crl->nssSignedCrl->crl);
+ SECAlgorithmID *algorithm = &nssCrl->signatureAlg;
+ SECItem *algBytes = &algorithm->algorithm;
+
+ if (!algBytes->data || !algBytes->len) {
+ PKIX_ERROR(PKIX_OIDBYTESLENGTH0);
+ }
+ PKIX_CHECK(PKIX_PL_OID_CreateBySECItem
+ (algBytes, &signatureAlgId, plContext),
+ PKIX_OIDCREATEFAILED);
+
+ /* save a cached copy in case it is asked for again */
+ crl->signatureAlgId = signatureAlgId;
+ signatureAlgId = NULL;
+ }
+ PKIX_OBJECT_UNLOCK(crl);
+ }
+ PKIX_INCREF(crl->signatureAlgId);
+ *pSignatureAlgId = crl->signatureAlgId;
+cleanup:
+ PKIX_DECREF(signatureAlgId);
+ PKIX_RETURN(CRL);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRL_GetCRLEntries
+ * DESCRIPTION:
+ *
+ * Retrieves a pointer to the List of CRLEntries found in the CRL pointed to
+ * by "crl" and stores it at "pCRLEntries". If there are no CRLEntries,
+ * this functions stores NULL at "pCRLEntries".
+ *
+ * PARAMETERS:
+ * "crl"
+ * Address of CRL whose CRL Entries are to be retrieved. Must be non-NULL.
+ * "pCRLEntries"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CRL Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CRL_GetCRLEntries(
+ PKIX_PL_CRL *crl,
+ PKIX_List **pCrlEntries,
+ void *plContext)
+{
+ PKIX_List *entryList = NULL;
+ CERTCrl *nssCrl = NULL;
+
+ PKIX_ENTER(CRL, "pkix_pl_CRL_GetCRLEntries");
+ PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pCrlEntries);
+
+ /* if we don't have a cached copy from before, we create one */
+ if (crl->crlEntryList == NULL) {
+
+ PKIX_OBJECT_LOCK(crl);
+
+ if (crl->crlEntryList == NULL){
+
+ nssCrl = &(crl->nssSignedCrl->crl);
+
+ PKIX_CHECK(pkix_pl_CRLEntry_Create
+ (nssCrl->entries, &entryList, plContext),
+ PKIX_CRLENTRYCREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_SetImmutable
+ (entryList, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ crl->crlEntryList = entryList;
+ }
+
+ PKIX_OBJECT_UNLOCK(crl);
+
+ }
+
+ PKIX_INCREF(crl->crlEntryList);
+
+ *pCrlEntries = crl->crlEntryList;
+
+cleanup:
+
+ PKIX_RETURN(CRL);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRL_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CRL_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_CRL *crl = NULL;
+
+ PKIX_ENTER(CRL, "pkix_pl_CRL_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CRL_TYPE, plContext),
+ PKIX_OBJECTNOTCRL);
+
+ crl = (PKIX_PL_CRL*)object;
+
+ PKIX_CRL_DEBUG("\t\tCalling CERT_DestroyCrl\n");
+ if (crl->nssSignedCrl) {
+ CERT_DestroyCrl(crl->nssSignedCrl);
+ }
+ if (crl->adoptedDerCrl) {
+ SECITEM_FreeItem(crl->adoptedDerCrl, PR_TRUE);
+ }
+ crl->nssSignedCrl = NULL;
+ crl->adoptedDerCrl = NULL;
+ crl->crlNumberAbsent = PKIX_FALSE;
+
+ PKIX_DECREF(crl->issuer);
+ PKIX_DECREF(crl->signatureAlgId);
+ PKIX_DECREF(crl->crlNumber);
+ PKIX_DECREF(crl->crlEntryList);
+ PKIX_DECREF(crl->critExtOids);
+ if (crl->derGenName) {
+ SECITEM_FreeItem(crl->derGenName, PR_TRUE);
+ }
+
+cleanup:
+
+ PKIX_RETURN(CRL);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRL_ToString_Helper
+ * DESCRIPTION:
+ *
+ * Helper function that creates a string representation of the CRL pointed
+ * to by "crl" and stores it at "pString".
+ *
+ * PARAMETERS
+ * "crl"
+ * Address of CRL whose string representation is desired.
+ * Must be non-NULL.
+ * "pString"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CRL Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CRL_ToString_Helper(
+ PKIX_PL_CRL *crl,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ char *asciiFormat = NULL;
+ PKIX_UInt32 crlVersion = 0;
+ PKIX_PL_X500Name *crlIssuer = NULL;
+ PKIX_PL_OID *nssSignatureAlgId = NULL;
+ PKIX_PL_BigInt *crlNumber = NULL;
+ PKIX_List *crlEntryList = NULL;
+ PKIX_List *critExtOIDs = NULL;
+ PKIX_PL_String *formatString = NULL;
+ PKIX_PL_String *crlIssuerString = NULL;
+ PKIX_PL_String *lastUpdateString = NULL;
+ PKIX_PL_String *nextUpdateString = NULL;
+ PKIX_PL_String *nssSignatureAlgIdString = NULL;
+ PKIX_PL_String *crlNumberString = NULL;
+ PKIX_PL_String *crlEntryListString = NULL;
+ PKIX_PL_String *critExtOIDsString = NULL;
+ PKIX_PL_String *crlString = NULL;
+
+ PKIX_ENTER(CRL, "pkix_pl_CRL_ToString_Helper");
+ PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pString);
+
+ asciiFormat =
+ "[\n"
+ "\tVersion: v%d\n"
+ "\tIssuer: %s\n"
+ "\tUpdate: [Last: %s\n"
+ "\t Next: %s]\n"
+ "\tSignatureAlgId: %s\n"
+ "\tCRL Number : %s\n"
+ "\n"
+ "\tEntry List: %s\n"
+ "\n"
+ "\tCritExtOIDs: %s\n"
+ "]\n";
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII,
+ asciiFormat,
+ 0,
+ &formatString,
+ plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ /* Version */
+ PKIX_CHECK(pkix_pl_CRL_GetVersion(crl, &crlVersion, plContext),
+ PKIX_CRLGETVERSIONFAILED);
+
+ /* Issuer */
+ PKIX_CHECK(PKIX_PL_CRL_GetIssuer(crl, &crlIssuer, plContext),
+ PKIX_CRLGETISSUERFAILED);
+
+ PKIX_CHECK(PKIX_PL_Object_ToString
+ ((PKIX_PL_Object *)crlIssuer, &crlIssuerString, plContext),
+ PKIX_X500NAMETOSTRINGFAILED);
+
+ /* This update - No Date object created, use nss data directly */
+ PKIX_CHECK(pkix_pl_Date_ToString_Helper
+ (&(crl->nssSignedCrl->crl.lastUpdate),
+ &lastUpdateString,
+ plContext),
+ PKIX_DATETOSTRINGHELPERFAILED);
+
+ /* Next update - No Date object created, use nss data directly */
+ PKIX_CHECK(pkix_pl_Date_ToString_Helper
+ (&(crl->nssSignedCrl->crl.nextUpdate),
+ &nextUpdateString,
+ plContext),
+ PKIX_DATETOSTRINGHELPERFAILED);
+
+ /* Signature Algorithm Id */
+ PKIX_CHECK(pkix_pl_CRL_GetSignatureAlgId
+ (crl, &nssSignatureAlgId, plContext),
+ PKIX_CRLGETSIGNATUREALGIDFAILED);
+
+ PKIX_CHECK(PKIX_PL_Object_ToString
+ ((PKIX_PL_Object *)nssSignatureAlgId,
+ &nssSignatureAlgIdString,
+ plContext),
+ PKIX_OIDTOSTRINGFAILED);
+
+ /* CRL Number */
+ PKIX_CHECK(PKIX_PL_CRL_GetCRLNumber
+ (crl, &crlNumber, plContext),
+ PKIX_CRLGETCRLNUMBERFAILED);
+
+ PKIX_TOSTRING(crlNumber, &crlNumberString, plContext,
+ PKIX_BIGINTTOSTRINGFAILED);
+
+ /* CRL Entries */
+ PKIX_CHECK(pkix_pl_CRL_GetCRLEntries(crl, &crlEntryList, plContext),
+ PKIX_CRLGETCRLENTRIESFAILED);
+
+ PKIX_TOSTRING(crlEntryList, &crlEntryListString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ /* CriticalExtensionOIDs */
+ PKIX_CHECK(PKIX_PL_CRL_GetCriticalExtensionOIDs
+ (crl, &critExtOIDs, plContext),
+ PKIX_CRLGETCRITICALEXTENSIONOIDSFAILED);
+
+ PKIX_TOSTRING(critExtOIDs, &critExtOIDsString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ PKIX_CHECK(PKIX_PL_Sprintf
+ (&crlString,
+ plContext,
+ formatString,
+ crlVersion + 1,
+ crlIssuerString,
+ lastUpdateString,
+ nextUpdateString,
+ nssSignatureAlgIdString,
+ crlNumberString,
+ crlEntryListString,
+ critExtOIDsString),
+ PKIX_SPRINTFFAILED);
+
+ *pString = crlString;
+
+cleanup:
+
+ PKIX_DECREF(crlIssuer);
+ PKIX_DECREF(nssSignatureAlgId);
+ PKIX_DECREF(crlNumber);
+ PKIX_DECREF(crlEntryList);
+ PKIX_DECREF(critExtOIDs);
+ PKIX_DECREF(crlIssuerString);
+ PKIX_DECREF(lastUpdateString);
+ PKIX_DECREF(nextUpdateString);
+ PKIX_DECREF(nssSignatureAlgIdString);
+ PKIX_DECREF(crlNumberString);
+ PKIX_DECREF(crlEntryListString);
+ PKIX_DECREF(critExtOIDsString);
+ PKIX_DECREF(formatString);
+
+ PKIX_RETURN(CRL);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRL_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CRL_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_String *crlString = NULL;
+ PKIX_PL_CRL *crl = NULL;
+
+ PKIX_ENTER(CRL, "pkix_pl_CRL_ToString");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CRL_TYPE, plContext),
+ PKIX_OBJECTNOTCRL);
+
+ crl = (PKIX_PL_CRL *) object;
+
+ PKIX_CHECK(pkix_pl_CRL_ToString_Helper(crl, &crlString, plContext),
+ PKIX_CRLTOSTRINGHELPERFAILED);
+
+ *pString = crlString;
+
+cleanup:
+
+ PKIX_RETURN(CRL);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRL_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CRL_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_CRL *crl = NULL;
+ PKIX_UInt32 certHash;
+ SECItem *crlDer = NULL;
+
+ PKIX_ENTER(CRL, "pkix_pl_CRL_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CRL_TYPE, plContext),
+ PKIX_OBJECTNOTCRL);
+
+ crl = (PKIX_PL_CRL *)object;
+ if (crl->adoptedDerCrl) {
+ crlDer = crl->adoptedDerCrl;
+ } else if (crl->nssSignedCrl && crl->nssSignedCrl->derCrl) {
+ crlDer = crl->nssSignedCrl->derCrl;
+ }
+ if (!crlDer || !crlDer->data) {
+ PKIX_ERROR(PKIX_CANNOTAQUIRECRLDER);
+ }
+
+ PKIX_CHECK(pkix_hash(crlDer->data, crlDer->len,
+ &certHash, plContext),
+ PKIX_ERRORINHASH);
+
+ *pHashcode = certHash;
+
+cleanup:
+
+ PKIX_RETURN(CRL);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRL_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CRL_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_PL_CRL *firstCrl = NULL;
+ PKIX_PL_CRL *secondCrl = NULL;
+ SECItem *crlDerOne = NULL, *crlDerTwo = NULL;
+ PKIX_UInt32 secondType;
+
+ PKIX_ENTER(CRL, "pkix_pl_CRL_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ /* test that firstObject is a CRL */
+ PKIX_CHECK(pkix_CheckType(firstObject, PKIX_CRL_TYPE, plContext),
+ PKIX_FIRSTOBJECTNOTCRL);
+
+ firstCrl = (PKIX_PL_CRL *)firstObject;
+ secondCrl = (PKIX_PL_CRL *)secondObject;
+
+ /*
+ * Since we know firstObject is a CRL, if both references are
+ * identical, they must be equal
+ */
+ if (firstCrl == secondCrl){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondCrl isn't a CRL, we don't throw an error.
+ * We simply return a Boolean result of FALSE
+ */
+ *pResult = PKIX_FALSE;
+ PKIX_CHECK(PKIX_PL_Object_GetType
+ ((PKIX_PL_Object *)secondCrl, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+ if (secondType != PKIX_CRL_TYPE) goto cleanup;
+
+ if (firstCrl->adoptedDerCrl) {
+ crlDerOne = firstCrl->adoptedDerCrl;
+ } else if (firstCrl->nssSignedCrl && firstCrl->nssSignedCrl->derCrl) {
+ crlDerOne = firstCrl->nssSignedCrl->derCrl;
+ }
+
+ if (secondCrl->adoptedDerCrl) {
+ crlDerTwo = secondCrl->adoptedDerCrl;
+ } else if (secondCrl->nssSignedCrl && secondCrl->nssSignedCrl->derCrl) {
+ crlDerTwo = secondCrl->nssSignedCrl->derCrl;
+ }
+
+ if (SECITEM_CompareItem(crlDerOne, crlDerTwo) == SECEqual) {
+ *pResult = PKIX_TRUE;
+ }
+
+cleanup:
+
+ PKIX_RETURN(CRL);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRL_RegisterSelf
+ *
+ * DESCRIPTION:
+ * Registers PKIX_CRL_TYPE and its related functions with systemClasses[]
+ * THREAD SAFETY:
+ *
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_CRL_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry *entry = &systemClasses[PKIX_CRL_TYPE];
+
+ PKIX_ENTER(CRL, "pkix_pl_CRL_RegisterSelf");
+
+ entry->description = "CRL";
+ entry->typeObjectSize = sizeof(PKIX_PL_CRL);
+ entry->destructor = pkix_pl_CRL_Destroy;
+ entry->equalsFunction = pkix_pl_CRL_Equals;
+ entry->hashcodeFunction = pkix_pl_CRL_Hashcode;
+ entry->toStringFunction = pkix_pl_CRL_ToString;
+ entry->duplicateFunction = pkix_duplicateImmutable;
+
+ PKIX_RETURN(CRL);
+}
+
+/*
+ * FUNCTION: PKIX_PL_CRL_VerifyUpdateTime (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_CRL_VerifyUpdateTime(
+ PKIX_PL_CRL *crl,
+ PKIX_PL_Date *date,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PRTime timeToCheck;
+ PRTime nextUpdate;
+ PRTime lastUpdate;
+ SECStatus status;
+ CERTCrl *nssCrl = NULL;
+ SECItem *nextUpdateDer = NULL;
+ PKIX_Boolean haveNextUpdate = PR_FALSE;
+
+ PKIX_ENTER(CRL, "PKIX_PL_CRL_VerifyUpdateTime");
+ PKIX_NULLCHECK_FOUR(crl, crl->nssSignedCrl, date, pResult);
+
+ /* Can call this function only with der been adopted. */
+ PORT_Assert(crl->adoptedDerCrl);
+
+ nssCrl = &(crl->nssSignedCrl->crl);
+ timeToCheck = date->nssTime;
+
+ /* nextUpdate can be NULL. Checking before using it */
+ nextUpdateDer = &nssCrl->nextUpdate;
+ if (nextUpdateDer->data && nextUpdateDer->len) {
+ haveNextUpdate = PR_TRUE;
+ status = DER_DecodeTimeChoice(&nextUpdate, nextUpdateDer);
+ if (status != SECSuccess) {
+ PKIX_ERROR(PKIX_DERDECODETIMECHOICEFORNEXTUPDATEFAILED);
+ }
+ }
+
+ status = DER_DecodeTimeChoice(&lastUpdate, &(nssCrl->lastUpdate));
+ if (status != SECSuccess) {
+ PKIX_ERROR(PKIX_DERDECODETIMECHOICEFORLASTUPDATEFAILED);
+ }
+
+ if (!haveNextUpdate || nextUpdate < timeToCheck) {
+ *pResult = PKIX_FALSE;
+ goto cleanup;
+ }
+
+ if (lastUpdate <= timeToCheck) {
+ *pResult = PKIX_TRUE;
+ } else {
+ *pResult = PKIX_FALSE;
+ }
+
+cleanup:
+
+ PKIX_RETURN(CRL);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRL_CreateWithSignedCRL
+ * DESCRIPTION:
+ *
+ * Creates a new CRL using the CERTSignedCrl pointed to by "nssSignedCrl"
+ * and stores it at "pCRL". If the decoding of the CERTSignedCrl fails,
+ * a PKIX_Error is returned.
+ *
+ * PARAMETERS:
+ * "nssSignedCrl"
+ * Address of CERTSignedCrl. Must be non-NULL.
+ * "adoptedDerCrl"
+ * SECItem ponter that if not NULL is indicating that memory used
+ * for der should be adopted by crl that is about to be created.
+ * "pCRL"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CRL Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_CRL_CreateWithSignedCRL(
+ CERTSignedCrl *nssSignedCrl,
+ SECItem *adoptedDerCrl,
+ SECItem *derGenName,
+ PKIX_PL_CRL **pCrl,
+ void *plContext)
+{
+ PKIX_PL_CRL *crl = NULL;
+
+ PKIX_ENTER(CRL, "pkix_pl_CRL_CreateWithSignedCRL");
+ PKIX_NULLCHECK_ONE(pCrl);
+
+ /* create a PKIX_PL_CRL object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_CRL_TYPE,
+ sizeof (PKIX_PL_CRL),
+ (PKIX_PL_Object **)&crl,
+ plContext),
+ PKIX_COULDNOTCREATECRLOBJECT);
+
+ /* populate the nssSignedCrl field */
+ crl->nssSignedCrl = nssSignedCrl;
+ crl->adoptedDerCrl = adoptedDerCrl;
+ crl->issuer = NULL;
+ crl->signatureAlgId = NULL;
+ crl->crlNumber = NULL;
+ crl->crlNumberAbsent = PKIX_FALSE;
+ crl->crlEntryList = NULL;
+ crl->critExtOids = NULL;
+ if (derGenName) {
+ crl->derGenName =
+ SECITEM_DupItem(derGenName);
+ if (!crl->derGenName) {
+ PKIX_ERROR(PKIX_ALLOCERROR);
+ }
+ }
+
+ *pCrl = crl;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(crl);
+ }
+
+ PKIX_RETURN(CRL);
+}
+
+/* --Public-CRL-Functions------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_CRL_Create (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_CRL_Create(
+ PKIX_PL_ByteArray *byteArray,
+ PKIX_PL_CRL **pCrl,
+ void *plContext)
+{
+ CERTSignedCrl *nssSignedCrl = NULL;
+ SECItem derItem, *derCrl = NULL;
+ PKIX_PL_CRL *crl = NULL;
+
+ PKIX_ENTER(CRL, "PKIX_PL_CRL_Create");
+ PKIX_NULLCHECK_TWO(byteArray, pCrl);
+
+ if (byteArray->length == 0){
+ PKIX_ERROR(PKIX_ZEROLENGTHBYTEARRAYFORCRLENCODING);
+ }
+ derItem.type = siBuffer;
+ derItem.data = byteArray->array;
+ derItem.len = byteArray->length;
+ derCrl = SECITEM_DupItem(&derItem);
+ if (!derCrl) {
+ PKIX_ERROR(PKIX_ALLOCERROR);
+ }
+ nssSignedCrl =
+ CERT_DecodeDERCrlWithFlags(NULL, derCrl, SEC_CRL_TYPE,
+ CRL_DECODE_DONT_COPY_DER |
+ CRL_DECODE_SKIP_ENTRIES);
+ if (!nssSignedCrl) {
+ PKIX_ERROR(PKIX_CERTDECODEDERCRLFAILED);
+ }
+ PKIX_CHECK(
+ pkix_pl_CRL_CreateWithSignedCRL(nssSignedCrl, derCrl, NULL,
+ &crl, plContext),
+ PKIX_CRLCREATEWITHSIGNEDCRLFAILED);
+ nssSignedCrl = NULL;
+ derCrl = NULL;
+ *pCrl = crl;
+
+cleanup:
+ if (derCrl) {
+ SECITEM_FreeItem(derCrl, PR_TRUE);
+ }
+ if (nssSignedCrl) {
+ SEC_DestroyCrl(nssSignedCrl);
+ }
+
+ PKIX_RETURN(CRL);
+}
+
+/*
+ * FUNCTION: PKIX_PL_CRL_GetIssuer (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_CRL_GetIssuer(
+ PKIX_PL_CRL *crl,
+ PKIX_PL_X500Name **pCRLIssuer,
+ void *plContext)
+{
+ PKIX_PL_String *crlString = NULL;
+ PKIX_PL_X500Name *issuer = NULL;
+ SECItem *derIssuerName = NULL;
+ CERTName *issuerName = NULL;
+
+ PKIX_ENTER(CRL, "PKIX_PL_CRL_GetIssuer");
+ PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pCRLIssuer);
+
+ /* Can call this function only with der been adopted. */
+ PORT_Assert(crl->adoptedDerCrl);
+
+ /* if we don't have a cached copy from before, we create one */
+ if (crl->issuer == NULL){
+
+ PKIX_OBJECT_LOCK(crl);
+
+ if (crl->issuer == NULL) {
+
+ issuerName = &crl->nssSignedCrl->crl.name;
+ derIssuerName = &crl->nssSignedCrl->crl.derName;
+
+ PKIX_CHECK(
+ PKIX_PL_X500Name_CreateFromCERTName(derIssuerName,
+ issuerName,
+ &issuer,
+ plContext),
+ PKIX_X500NAMECREATEFROMCERTNAMEFAILED);
+
+ /* save a cached copy in case it is asked for again */
+ crl->issuer = issuer;
+ }
+
+ PKIX_OBJECT_UNLOCK(crl);
+
+ }
+
+ PKIX_INCREF(crl->issuer);
+
+ *pCRLIssuer = crl->issuer;
+
+cleanup:
+
+ PKIX_DECREF(crlString);
+
+ PKIX_RETURN(CRL);
+}
+
+
+/*
+ * FUNCTION: PKIX_PL_CRL_GetCriticalExtensionOIDs
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_CRL_GetCriticalExtensionOIDs(
+ PKIX_PL_CRL *crl,
+ PKIX_List **pExtensions, /* list of PKIX_PL_OID */
+ void *plContext)
+{
+ PKIX_List *oidsList = NULL;
+ CERTCertExtension **extensions = NULL;
+ CERTCrl *nssSignedCrl = NULL;
+
+ PKIX_ENTER(CRL, "PKIX_PL_CRL_GetCriticalExtensionOIDs");
+ PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pExtensions);
+
+ /* Can call this function only with der been adopted. */
+ PORT_Assert(crl->adoptedDerCrl);
+
+ /* if we don't have a cached copy from before, we create one */
+ if (crl->critExtOids == NULL) {
+
+ PKIX_OBJECT_LOCK(crl);
+
+ nssSignedCrl = &(crl->nssSignedCrl->crl);
+ extensions = nssSignedCrl->extensions;
+
+ if (crl->critExtOids == NULL) {
+
+ PKIX_CHECK(pkix_pl_OID_GetCriticalExtensionOIDs
+ (extensions, &oidsList, plContext),
+ PKIX_GETCRITICALEXTENSIONOIDSFAILED);
+
+ crl->critExtOids = oidsList;
+ }
+
+ PKIX_OBJECT_UNLOCK(crl);
+
+ }
+
+ /* We should return a copy of the List since this list changes */
+ PKIX_DUPLICATE(crl->critExtOids, pExtensions, plContext,
+ PKIX_OBJECTDUPLICATELISTFAILED);
+
+cleanup:
+
+ PKIX_RETURN(CRL);
+}
+
+/*
+ * FUNCTION: PKIX_PL_CRL_VerifySignature (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_CRL_VerifySignature(
+ PKIX_PL_CRL *crl,
+ PKIX_PL_PublicKey *pubKey,
+ void *plContext)
+{
+ PKIX_PL_CRL *cachedCrl = NULL;
+ PKIX_Error *verifySig = NULL;
+ PKIX_Error *cachedSig = NULL;
+ PKIX_Boolean crlEqual = PKIX_FALSE;
+ PKIX_Boolean crlInHash= PKIX_FALSE;
+ CERTSignedCrl *nssSignedCrl = NULL;
+ SECKEYPublicKey *nssPubKey = NULL;
+ CERTSignedData *tbsCrl = NULL;
+ void* wincx = NULL;
+ SECStatus status;
+
+ PKIX_ENTER(CRL, "PKIX_PL_CRL_VerifySignature");
+ PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pubKey);
+
+ /* Can call this function only with der been adopted. */
+ PORT_Assert(crl->adoptedDerCrl);
+
+ verifySig = PKIX_PL_HashTable_Lookup
+ (cachedCrlSigTable,
+ (PKIX_PL_Object *) pubKey,
+ (PKIX_PL_Object **) &cachedCrl,
+ plContext);
+
+ if (cachedCrl != NULL && verifySig == NULL) {
+ /* Cached Signature Table lookup succeed */
+ PKIX_EQUALS(crl, cachedCrl, &crlEqual, plContext,
+ PKIX_OBJECTEQUALSFAILED);
+ if (crlEqual == PKIX_TRUE) {
+ goto cleanup;
+ }
+ /* Different PubKey may hash to same value, skip add */
+ crlInHash = PKIX_TRUE;
+ }
+
+ nssSignedCrl = crl->nssSignedCrl;
+ tbsCrl = &nssSignedCrl->signatureWrap;
+
+ PKIX_CRL_DEBUG("\t\tCalling SECKEY_ExtractPublicKey\n");
+ nssPubKey = SECKEY_ExtractPublicKey(pubKey->nssSPKI);
+ if (!nssPubKey){
+ PKIX_ERROR(PKIX_SECKEYEXTRACTPUBLICKEYFAILED);
+ }
+
+ PKIX_CHECK(pkix_pl_NssContext_GetWincx
+ ((PKIX_PL_NssContext *)plContext, &wincx),
+ PKIX_NSSCONTEXTGETWINCXFAILED);
+
+ PKIX_CRL_DEBUG("\t\tCalling CERT_VerifySignedDataWithPublicKey\n");
+ status = CERT_VerifySignedDataWithPublicKey(tbsCrl, nssPubKey, wincx);
+
+ if (status != SECSuccess) {
+ PORT_SetError(SEC_ERROR_BAD_SIGNATURE);
+ PKIX_ERROR(PKIX_SIGNATUREDIDNOTVERIFYWITHTHEPUBLICKEY);
+ }
+
+ if (crlInHash == PKIX_FALSE) {
+ cachedSig = PKIX_PL_HashTable_Add
+ (cachedCrlSigTable,
+ (PKIX_PL_Object *) pubKey,
+ (PKIX_PL_Object *) crl,
+ plContext);
+
+ if (cachedSig != NULL) {
+ PKIX_DEBUG("PKIX_PL_HashTable_Add skipped: entry existed\n");
+ }
+ }
+
+cleanup:
+
+ if (nssPubKey){
+ PKIX_CRL_DEBUG("\t\tCalling SECKEY_DestroyPublicKey\n");
+ SECKEY_DestroyPublicKey(nssPubKey);
+ nssPubKey = NULL;
+ }
+
+ PKIX_DECREF(cachedCrl);
+ PKIX_DECREF(verifySig);
+ PKIX_DECREF(cachedSig);
+
+ PKIX_RETURN(CRL);
+}
+
+PKIX_Error*
+PKIX_PL_CRL_ReleaseDerCrl(PKIX_PL_CRL *crl,
+ SECItem **derCrl,
+ void *plContext)
+{
+ PKIX_ENTER(CRL, "PKIX_PL_CRL_ReleaseDerCrl");
+ *derCrl = crl->adoptedDerCrl;
+ crl->adoptedDerCrl = NULL;
+
+ PKIX_RETURN(CRL);
+}
+
+PKIX_Error*
+PKIX_PL_CRL_AdoptDerCrl(PKIX_PL_CRL *crl,
+ SECItem *derCrl,
+ void *plContext)
+{
+ PKIX_ENTER(CRL, "PKIX_PL_CRL_AquireDerCrl");
+ if (crl->adoptedDerCrl) {
+ PKIX_ERROR(PKIX_CANNOTAQUIRECRLDER);
+ }
+ crl->adoptedDerCrl = derCrl;
+cleanup:
+ PKIX_RETURN(CRL);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.h
new file mode 100644
index 000000000..a45059ea0
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crl.h
@@ -0,0 +1,48 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_crl.h
+ *
+ * CRL Object Type Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_CRL_H
+#define _PKIX_PL_CRL_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_CRLStruct {
+ CERTSignedCrl *nssSignedCrl;
+ PKIX_PL_X500Name *issuer;
+ PKIX_PL_OID *signatureAlgId;
+ PKIX_PL_BigInt *crlNumber;
+ PKIX_Boolean crlNumberAbsent;
+ PKIX_List *crlEntryList; /* list of PKIX_PL_CRLEntry */
+ PKIX_List *critExtOids;
+ SECItem *adoptedDerCrl;
+ SECItem *derGenName; /* der of general name which was used
+ * to download the crl. */
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_CRL_RegisterSelf(void *plContext);
+
+PKIX_Error *
+pkix_pl_CRL_CreateWithSignedCRL(CERTSignedCrl *nssSignedCrl,
+ SECItem *derCrl,
+ SECItem *derGenName,
+ PKIX_PL_CRL **pCrl,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_CRL_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.c
new file mode 100644
index 000000000..4f29de284
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.c
@@ -0,0 +1,151 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_crldp.c
+ *
+ * Crl DP Object Functions
+ *
+ */
+
+#include "pkix_pl_crldp.h"
+
+static PKIX_Error *
+pkix_pl_CrlDp_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ pkix_pl_CrlDp *crldp = NULL;
+
+ PKIX_ENTER(CRLCHECKER, "pkix_CrlDp_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ /* Check that this object is a default CRL checker state */
+ PKIX_CHECK(
+ pkix_CheckType(object, PKIX_CRLDP_TYPE, plContext),
+ PKIX_OBJECTNOTCRLCHECKER);
+
+ crldp = (pkix_pl_CrlDp *)object;
+ if (crldp->distPointType == relativeDistinguishedName) {
+ CERT_DestroyName(crldp->name.issuerName);
+ crldp->name.issuerName = NULL;
+ }
+ crldp->nssdp = NULL;
+cleanup:
+ PKIX_RETURN(CRLCHECKER);
+}
+
+/*
+ * FUNCTION: pkix_pl_CrlDp_RegisterSelf
+ *
+ * DESCRIPTION:
+ * Registers PKIX_CRLDP_TYPE and its related functions
+ * with systemClasses[]
+ *
+ * THREAD SAFETY:
+ * Not Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_CrlDp_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry* entry = &systemClasses[PKIX_CRLDP_TYPE];
+
+ PKIX_ENTER(CRLCHECKER, "pkix_CrlDp_RegisterSelf");
+
+ entry->description = "CrlDistPoint";
+ entry->typeObjectSize = sizeof(pkix_pl_CrlDp);
+ entry->destructor = pkix_pl_CrlDp_Destroy;
+ entry->duplicateFunction = pkix_duplicateImmutable;
+
+ PKIX_RETURN(CRLCHECKER);
+}
+
+
+
+PKIX_Error *
+pkix_pl_CrlDp_Create(
+ const CRLDistributionPoint *dp,
+ const CERTName *certIssuerName,
+ pkix_pl_CrlDp **pPkixDP,
+ void *plContext)
+{
+ PLArenaPool *rdnArena = NULL;
+ CERTName *issuerNameCopy = NULL;
+ pkix_pl_CrlDp *dpl = NULL;
+
+ /* Need to save the following info to update crl cache:
+ * - reasons if partitioned(but can not return revocation check
+ * success if not all crl are downloaded)
+ * - issuer name if different from issuer of the cert
+ * - url to upload a crl if needed.
+ * */
+ PKIX_ENTER(CRLDP, "pkix_pl_CrlDp_Create");
+ PKIX_NULLCHECK_ONE(dp);
+
+ PKIX_CHECK(
+ PKIX_PL_Object_Alloc(PKIX_CRLDP_TYPE,
+ sizeof (pkix_pl_CrlDp),
+ (PKIX_PL_Object **)&dpl,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ dpl->nssdp = dp;
+ dpl->isPartitionedByReasonCode = PKIX_FALSE;
+ if (dp->reasons.data) {
+ dpl->isPartitionedByReasonCode = PKIX_TRUE;
+ }
+ if (dp->distPointType == generalName) {
+ dpl->distPointType = generalName;
+ dpl->name.fullName = dp->distPoint.fullName;
+ } else {
+ SECStatus rv;
+ const CERTName *issuerName = NULL;
+ const CERTRDN *relName = &dp->distPoint.relativeName;
+
+ if (dp->crlIssuer) {
+ if (dp->crlIssuer->l.next) {
+ /* Violate RFC 5280: in this case crlIssuer
+ * should have only one name and should be
+ * a distinguish name. */
+ PKIX_ERROR(PKIX_NOTCONFORMINGCRLDP);
+ }
+ issuerName = &dp->crlIssuer->name.directoryName;
+ } else {
+ issuerName = certIssuerName;
+ }
+ rdnArena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (!rdnArena) {
+ PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
+ }
+ issuerNameCopy = (CERTName *)PORT_ArenaZNew(rdnArena, CERTName);
+ if (!issuerNameCopy) {
+ PKIX_ERROR(PKIX_ALLOCERROR);
+ }
+ rv = CERT_CopyName(rdnArena, issuerNameCopy, (CERTName*)issuerName);
+ if (rv == SECFailure) {
+ PKIX_ERROR(PKIX_ALLOCERROR);
+ }
+ rv = CERT_AddRDN(issuerNameCopy, (CERTRDN*)relName);
+ if (rv == SECFailure) {
+ PKIX_ERROR(PKIX_ALLOCERROR);
+ }
+ dpl->distPointType = relativeDistinguishedName;
+ dpl->name.issuerName = issuerNameCopy;
+ rdnArena = NULL;
+ }
+ *pPkixDP = dpl;
+ dpl = NULL;
+
+cleanup:
+ if (rdnArena) {
+ PORT_FreeArena(rdnArena, PR_FALSE);
+ }
+ PKIX_DECREF(dpl);
+
+ PKIX_RETURN(CRLDP);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.h
new file mode 100644
index 000000000..49cd9d2cd
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crldp.h
@@ -0,0 +1,53 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_crldp.h
+ *
+ * Crp DP Object Definitions
+ *
+ */
+#include "pkix_pl_common.h"
+
+#ifndef _PKIX_PL_CRLDP_H
+#define _PKIX_PL_CRLDP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* CRLDP object can not be used without holding a reference
+ * to the pkix certificate they belong to. The memory for dp der
+ * object is allocated on nssCert certificate - a member of
+ * PKIX_PL_Cert struct. */
+typedef struct pkix_pl_CrlDpStruct {
+ /* reference to decoded crldp that allocated on nssCert arena. */
+ const CRLDistributionPoint *nssdp;
+ DistributionPointTypes distPointType;
+ union {
+ CERTGeneralName *fullName;
+ /* if dp is a relative name, the issuerName is a merged value
+ * of crlIssuer and a relative name. Must be destroyed by CrlDp
+ * destructor. */
+ CERTName *issuerName;
+ } name;
+ PKIX_Boolean isPartitionedByReasonCode;
+} pkix_pl_CrlDp;
+
+
+PKIX_Error *
+pkix_pl_CrlDp_RegisterSelf(void *plContext);
+
+/* Parses CRLDistributionPoint structure and creaetes
+ * pkix_pl_CrlDp object. */
+PKIX_Error *
+pkix_pl_CrlDp_Create(const CRLDistributionPoint *dp,
+ const CERTName *certIssuerName,
+ pkix_pl_CrlDp **pPkixDP,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_CRLDP_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.c
new file mode 100644
index 000000000..e2b3e0268
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.c
@@ -0,0 +1,880 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_crlentry.c
+ *
+ * CRLENTRY Function Definitions
+ *
+ */
+
+#include "pkix_pl_crlentry.h"
+
+/* --Private-CRLEntry-Functions------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_CRLEntry_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CRLEntry_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_CRLEntry *crlEntry = NULL;
+
+ PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CRLENTRY_TYPE, plContext),
+ PKIX_OBJECTNOTCRLENTRY);
+
+ crlEntry = (PKIX_PL_CRLEntry*)object;
+
+ /* crlEntry->nssCrlEntry is freed by NSS when freeing CRL */
+ crlEntry->userReasonCode = 0;
+ crlEntry->userReasonCodeAbsent = PKIX_FALSE;
+ crlEntry->nssCrlEntry = NULL;
+ PKIX_DECREF(crlEntry->serialNumber);
+ PKIX_DECREF(crlEntry->critExtOids);
+
+cleanup:
+
+ PKIX_RETURN(CRLENTRY);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRLEntry_ToString_Helper
+ *
+ * DESCRIPTION:
+ * Helper function that creates a string representation of the CRLEntry
+ * pointed to by "crlEntry" and stores it at "pString".
+ *
+ * PARAMETERS
+ * "crlEntry"
+ * Address of CRLEntry whose string representation is desired.
+ * Must be non-NULL.
+ * "pString"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CRLEntry Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_CRLEntry_ToString_Helper(
+ PKIX_PL_CRLEntry *crlEntry,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ char *asciiFormat = NULL;
+ PKIX_List *critExtOIDs = NULL;
+ PKIX_PL_String *crlEntryString = NULL;
+ PKIX_PL_String *formatString = NULL;
+ PKIX_PL_String *crlSerialNumberString = NULL;
+ PKIX_PL_String *crlRevocationDateString = NULL;
+ PKIX_PL_String *critExtOIDsString = NULL;
+ PKIX_Int32 reasonCode = 0;
+
+ PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_ToString_Helper");
+ PKIX_NULLCHECK_FOUR
+ (crlEntry,
+ crlEntry->serialNumber,
+ crlEntry->nssCrlEntry,
+ pString);
+
+ asciiFormat =
+ "\n\t[\n"
+ "\tSerialNumber: %s\n"
+ "\tReasonCode: %d\n"
+ "\tRevocationDate: %s\n"
+ "\tCritExtOIDs: %s\n"
+ "\t]\n\t";
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII,
+ asciiFormat,
+ 0,
+ &formatString,
+ plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ /* SerialNumber */
+ PKIX_CHECK(PKIX_PL_Object_ToString
+ ((PKIX_PL_Object *)crlEntry->serialNumber,
+ &crlSerialNumberString,
+ plContext),
+ PKIX_BIGINTTOSTRINGHELPERFAILED);
+
+ /* RevocationDate - No Date object created, use nss data directly */
+ PKIX_CHECK(pkix_pl_Date_ToString_Helper
+ (&(crlEntry->nssCrlEntry->revocationDate),
+ &crlRevocationDateString,
+ plContext),
+ PKIX_DATETOSTRINGHELPERFAILED);
+
+ /* CriticalExtensionOIDs */
+ PKIX_CHECK(PKIX_PL_CRLEntry_GetCriticalExtensionOIDs
+ (crlEntry, &critExtOIDs, plContext),
+ PKIX_CRLENTRYGETCRITICALEXTENSIONOIDSFAILED);
+
+ PKIX_TOSTRING(critExtOIDs, &critExtOIDsString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ /* Revocation Reason Code */
+ PKIX_CHECK(PKIX_PL_CRLEntry_GetCRLEntryReasonCode
+ (crlEntry, &reasonCode, plContext),
+ PKIX_CRLENTRYGETCRLENTRYREASONCODEFAILED);
+
+ PKIX_CHECK(PKIX_PL_Sprintf
+ (&crlEntryString,
+ plContext,
+ formatString,
+ crlSerialNumberString,
+ reasonCode,
+ crlRevocationDateString,
+ critExtOIDsString),
+ PKIX_SPRINTFFAILED);
+
+ *pString = crlEntryString;
+
+cleanup:
+
+ PKIX_DECREF(critExtOIDs);
+ PKIX_DECREF(crlSerialNumberString);
+ PKIX_DECREF(crlRevocationDateString);
+ PKIX_DECREF(critExtOIDsString);
+ PKIX_DECREF(formatString);
+
+ PKIX_RETURN(CRLENTRY);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRLEntry_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CRLEntry_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_String *crlEntryString = NULL;
+ PKIX_PL_CRLEntry *crlEntry = NULL;
+
+ PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_ToString");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CRLENTRY_TYPE, plContext),
+ PKIX_OBJECTNOTCRLENTRY);
+
+ crlEntry = (PKIX_PL_CRLEntry *) object;
+
+ PKIX_CHECK(pkix_pl_CRLEntry_ToString_Helper
+ (crlEntry, &crlEntryString, plContext),
+ PKIX_CRLENTRYTOSTRINGHELPERFAILED);
+
+ *pString = crlEntryString;
+
+cleanup:
+
+ PKIX_RETURN(CRLENTRY);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRLEntry_Extensions_Hashcode
+ * DESCRIPTION:
+ *
+ * For each CRL Entry extension stored at NSS structure CERTCertExtension,
+ * get its derbyte data and do the hash.
+ *
+ * PARAMETERS
+ * "extensions"
+ * Address of arrray of CERTCertExtension whose hash value is desired.
+ * Must be non-NULL.
+ * "pHashValue"
+ * Address where the final hash value is returned. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Conditional Thread Safe
+ * Though the value of extensions once created is not supposed to change,
+ * it may be de-allocated while we are accessing it. But since we are
+ * validating the object, it is unlikely we or someone is de-allocating
+ * at the moment.
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an OID Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CRLEntry_Extensions_Hashcode(
+ CERTCertExtension **extensions,
+ PKIX_UInt32 *pHashValue,
+ void *plContext)
+{
+ CERTCertExtension *extension = NULL;
+ PLArenaPool *arena = NULL;
+ PKIX_UInt32 extHash = 0;
+ PKIX_UInt32 hashValue = 0;
+ SECItem *derBytes = NULL;
+ SECItem *resultSecItem = NULL;
+
+ PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Extensions_Hashcode");
+ PKIX_NULLCHECK_TWO(extensions, pHashValue);
+
+ if (extensions) {
+
+ PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_NewArena\n");
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ while (*extensions) {
+
+ extension = *extensions++;
+
+ PKIX_NULLCHECK_ONE(extension);
+
+ PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_ArenaZNew\n");
+ derBytes = PORT_ArenaZNew(arena, SECItem);
+ if (derBytes == NULL) {
+ PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
+ }
+
+ PKIX_CRLENTRY_DEBUG
+ ("\t\tCalling SEC_ASN1EncodeItem\n");
+ resultSecItem = SEC_ASN1EncodeItem
+ (arena,
+ derBytes,
+ extension,
+ CERT_CertExtensionTemplate);
+
+ if (resultSecItem == NULL){
+ PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED);
+ }
+
+ PKIX_CHECK(pkix_hash
+ (derBytes->data,
+ derBytes->len,
+ &extHash,
+ plContext),
+ PKIX_HASHFAILED);
+
+ hashValue += (extHash << 7);
+
+ }
+ }
+
+ *pHashValue = hashValue;
+
+cleanup:
+
+ if (arena){
+ /* Note that freeing the arena also frees derBytes */
+ PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_FreeArena\n");
+ PORT_FreeArena(arena, PR_FALSE);
+ arena = NULL;
+ }
+ PKIX_RETURN(CRLENTRY);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRLEntry_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CRLEntry_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ SECItem *nssDate = NULL;
+ PKIX_PL_CRLEntry *crlEntry = NULL;
+ PKIX_UInt32 crlEntryHash;
+ PKIX_UInt32 hashValue;
+ PKIX_Int32 reasonCode = 0;
+
+ PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_CRLENTRY_TYPE, plContext),
+ PKIX_OBJECTNOTCRLENTRY);
+
+ crlEntry = (PKIX_PL_CRLEntry *)object;
+
+ PKIX_NULLCHECK_ONE(crlEntry->nssCrlEntry);
+ nssDate = &(crlEntry->nssCrlEntry->revocationDate);
+
+ PKIX_NULLCHECK_ONE(nssDate->data);
+
+ PKIX_CHECK(pkix_hash
+ ((const unsigned char *)nssDate->data,
+ nssDate->len,
+ &crlEntryHash,
+ plContext),
+ PKIX_ERRORGETTINGHASHCODE);
+
+ PKIX_CHECK(PKIX_PL_Object_Hashcode
+ ((PKIX_PL_Object *)crlEntry->serialNumber,
+ &hashValue,
+ plContext),
+ PKIX_OBJECTHASHCODEFAILED);
+
+ crlEntryHash += (hashValue << 7);
+
+ hashValue = 0;
+
+ if (crlEntry->nssCrlEntry->extensions) {
+
+ PKIX_CHECK(pkix_pl_CRLEntry_Extensions_Hashcode
+ (crlEntry->nssCrlEntry->extensions, &hashValue, plContext),
+ PKIX_CRLENTRYEXTENSIONSHASHCODEFAILED);
+ }
+
+ crlEntryHash += (hashValue << 7);
+
+ PKIX_CHECK(PKIX_PL_CRLEntry_GetCRLEntryReasonCode
+ (crlEntry, &reasonCode, plContext),
+ PKIX_CRLENTRYGETCRLENTRYREASONCODEFAILED);
+
+ crlEntryHash += (reasonCode + 777) << 3;
+
+ *pHashcode = crlEntryHash;
+
+cleanup:
+
+ PKIX_RETURN(CRLENTRY);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRLENTRY_Extensions_Equals
+ * DESCRIPTION:
+ *
+ * Compare each extension's DERbyte data in "firstExtensions" with extension
+ * in "secondExtensions" in sequential order and store the result in
+ * "pResult".
+ *
+ * PARAMETERS
+ * "firstExtensions"
+ * Address of first NSS structure CERTCertExtension to be compared.
+ * Must be non-NULL.
+ * "secondExtensions"
+ * Address of second NSS structure CERTCertExtension to be compared.
+ * Must be non-NULL.
+ * "pResult"
+ * Address where the comparison result is returned. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Conditionally Thread Safe
+ * Though the value of extensions once created is not supposed to change,
+ * it may be de-allocated while we are accessing it. But since we are
+ * validating the object, it is unlikely we or someone is de-allocating
+ * at the moment.
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an OID Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CRLEntry_Extensions_Equals(
+ CERTCertExtension **extensions1,
+ CERTCertExtension **extensions2,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ CERTCertExtension **firstExtensions;
+ CERTCertExtension **secondExtensions;
+ CERTCertExtension *firstExtension = NULL;
+ CERTCertExtension *secondExtension = NULL;
+ PLArenaPool *arena = NULL;
+ PKIX_Boolean cmpResult = PKIX_FALSE;
+ SECItem *firstDerBytes = NULL;
+ SECItem *secondDerBytes = NULL;
+ SECItem *firstResultSecItem = NULL;
+ SECItem *secondResultSecItem = NULL;
+ PKIX_UInt32 firstNumExt = 0;
+ PKIX_UInt32 secondNumExt = 0;
+ SECComparison secResult;
+
+ PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Extensions_Equals");
+ PKIX_NULLCHECK_THREE(extensions1, extensions2, pResult);
+
+ firstExtensions = extensions1;
+ secondExtensions = extensions2;
+
+ if (firstExtensions) {
+ while (*firstExtensions) {
+ firstExtension = *firstExtensions++;
+ firstNumExt++;
+ }
+ }
+
+ if (secondExtensions) {
+ while (*secondExtensions) {
+ secondExtension = *secondExtensions++;
+ secondNumExt++;
+ }
+ }
+
+ if (firstNumExt != secondNumExt) {
+ *pResult = PKIX_FALSE;
+ goto cleanup;
+ }
+
+ if (firstNumExt == 0 && secondNumExt == 0) {
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /* now have equal number, but non-zero extension items to compare */
+
+ firstExtensions = extensions1;
+ secondExtensions = extensions2;
+
+ cmpResult = PKIX_TRUE;
+
+ PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_NewArena\n");
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE*2);
+ if (arena == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ while (firstNumExt--) {
+
+ firstExtension = *firstExtensions++;
+ secondExtension = *secondExtensions++;
+
+ PKIX_NULLCHECK_TWO(firstExtension, secondExtension);
+
+ PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_ArenaZNew\n");
+ firstDerBytes = PORT_ArenaZNew(arena, SECItem);
+ if (firstDerBytes == NULL) {
+ PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
+ }
+
+ PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_ArenaZNew\n");
+ secondDerBytes = PORT_ArenaZNew(arena, SECItem);
+ if (secondDerBytes == NULL) {
+ PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
+ }
+
+ PKIX_CRLENTRY_DEBUG
+ ("\t\tCalling SEC_ASN1EncodeItem\n");
+ firstResultSecItem = SEC_ASN1EncodeItem
+ (arena,
+ firstDerBytes,
+ firstExtension,
+ CERT_CertExtensionTemplate);
+
+ if (firstResultSecItem == NULL){
+ PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED);
+ }
+
+ PKIX_CRLENTRY_DEBUG
+ ("\t\tCalling SEC_ASN1EncodeItem\n");
+ secondResultSecItem = SEC_ASN1EncodeItem
+ (arena,
+ secondDerBytes,
+ secondExtension,
+ CERT_CertExtensionTemplate);
+
+ if (secondResultSecItem == NULL){
+ PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED);
+ }
+
+ PKIX_CRLENTRY_DEBUG("\t\tCalling SECITEM_CompareItem\n");
+ secResult = SECITEM_CompareItem
+ (firstResultSecItem, secondResultSecItem);
+
+ if (secResult != SECEqual) {
+ cmpResult = PKIX_FALSE;
+ break;
+ }
+
+ }
+
+ *pResult = cmpResult;
+
+cleanup:
+
+ if (arena){
+ /* Note that freeing the arena also frees derBytes */
+ PKIX_CRLENTRY_DEBUG("\t\tCalling PORT_FreeArena\n");
+ PORT_FreeArena(arena, PR_FALSE);
+ arena = NULL;
+ }
+
+ PKIX_RETURN(CRLENTRY);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRLEntry_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CRLEntry_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_PL_CRLEntry *firstCrlEntry = NULL;
+ PKIX_PL_CRLEntry *secondCrlEntry = NULL;
+ PKIX_UInt32 secondType;
+ PKIX_Boolean cmpResult = PKIX_FALSE;
+
+ PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ /* test that firstObject is a CRLEntry */
+ PKIX_CHECK(pkix_CheckType(firstObject, PKIX_CRLENTRY_TYPE, plContext),
+ PKIX_FIRSTOBJECTNOTCRLENTRY);
+
+ firstCrlEntry = (PKIX_PL_CRLEntry *)firstObject;
+ secondCrlEntry = (PKIX_PL_CRLEntry *)secondObject;
+
+ PKIX_NULLCHECK_TWO
+ (firstCrlEntry->nssCrlEntry, secondCrlEntry->nssCrlEntry);
+
+ /*
+ * Since we know firstObject is a CRLEntry, if both references are
+ * identical, they must be equal
+ */
+ if (firstCrlEntry == secondCrlEntry){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondCrlEntry isn't a CRL Entry, we don't throw an error.
+ * We simply return a Boolean result of FALSE
+ */
+ *pResult = PKIX_FALSE;
+ PKIX_CHECK(PKIX_PL_Object_GetType
+ ((PKIX_PL_Object *)secondCrlEntry, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+ if (secondType != PKIX_CRLENTRY_TYPE) goto cleanup;
+
+ /* Compare userSerialNumber */
+ PKIX_CRLENTRY_DEBUG("\t\tCalling SECITEM_CompareItem\n");
+ if (SECITEM_CompareItem(
+ &(((PKIX_PL_CRLEntry *)firstCrlEntry)->nssCrlEntry->serialNumber),
+ &(((PKIX_PL_CRLEntry *)secondCrlEntry)->nssCrlEntry->serialNumber))
+ != SECEqual) {
+ *pResult = PKIX_FALSE;
+ goto cleanup;
+ }
+
+ /* Compare revocationDate */
+ PKIX_CRLENTRY_DEBUG("\t\tCalling SECITEM_CompareItem\n");
+ if (SECITEM_CompareItem
+ (&(((PKIX_PL_CRLEntry *)firstCrlEntry)->nssCrlEntry->
+ revocationDate),
+ &(((PKIX_PL_CRLEntry *)secondCrlEntry)->nssCrlEntry->
+ revocationDate))
+ != SECEqual) {
+ *pResult = PKIX_FALSE;
+ goto cleanup;
+ }
+
+ /* Compare Critical Extension List */
+ PKIX_CHECK(pkix_pl_CRLEntry_Extensions_Equals
+ (firstCrlEntry->nssCrlEntry->extensions,
+ secondCrlEntry->nssCrlEntry->extensions,
+ &cmpResult,
+ plContext),
+ PKIX_CRLENTRYEXTENSIONSEQUALSFAILED);
+
+ if (cmpResult != PKIX_TRUE){
+ *pResult = PKIX_FALSE;
+ goto cleanup;
+ }
+
+ cmpResult = (firstCrlEntry->userReasonCode ==
+ secondCrlEntry->userReasonCode);
+
+ *pResult = cmpResult;
+
+cleanup:
+
+ PKIX_RETURN(CRLENTRY);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRLEntry_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_CRLEntry_TYPE and its related functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_CRLEntry_RegisterSelf(void *plContext)
+{
+
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_RegisterSelf");
+
+ entry.description = "CRLEntry";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_CRLEntry);
+ entry.destructor = pkix_pl_CRLEntry_Destroy;
+ entry.equalsFunction = pkix_pl_CRLEntry_Equals;
+ entry.hashcodeFunction = pkix_pl_CRLEntry_Hashcode;
+ entry.toStringFunction = pkix_pl_CRLEntry_ToString;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_CRLENTRY_TYPE] = entry;
+
+ PKIX_RETURN(CRLENTRY);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRLEntry_CreateEntry
+ * DESCRIPTION:
+ *
+ * Creates a new CRLEntry using the CertCrlEntry pointed to by "nssCrlEntry"
+ * and stores it at "pCrlEntry". Once created, a CRLEntry is immutable.
+ *
+ * revokedCertificates SEQUENCE OF SEQUENCE {
+ * userCertificate CertificateSerialNumber,
+ * revocationDate Time,
+ * crlEntryExtensions Extensions OPTIONAL
+ * -- if present, MUST be v2
+ *
+ * PARAMETERS:
+ * "nssCrlEntry"
+ * Address of CERTCrlEntry representing an NSS CRL entry.
+ * Must be non-NULL.
+ * "pCrlEntry"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CRLEntry Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CRLEntry_CreateEntry(
+ CERTCrlEntry *nssCrlEntry, /* entry data to be created from */
+ PKIX_PL_CRLEntry **pCrlEntry,
+ void *plContext)
+{
+ PKIX_PL_CRLEntry *crlEntry = NULL;
+
+ PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_CreateEntry");
+ PKIX_NULLCHECK_TWO(nssCrlEntry, pCrlEntry);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_CRLENTRY_TYPE,
+ sizeof (PKIX_PL_CRLEntry),
+ (PKIX_PL_Object **)&crlEntry,
+ plContext),
+ PKIX_COULDNOTCREATECRLENTRYOBJECT);
+
+ crlEntry->nssCrlEntry = nssCrlEntry;
+ crlEntry->serialNumber = NULL;
+ crlEntry->critExtOids = NULL;
+ crlEntry->userReasonCode = 0;
+ crlEntry->userReasonCodeAbsent = PKIX_FALSE;
+
+ *pCrlEntry = crlEntry;
+
+cleanup:
+
+ PKIX_RETURN(CRLENTRY);
+}
+
+/*
+ * FUNCTION: pkix_pl_CRLEntry_Create
+ * DESCRIPTION:
+ *
+ * Creates a List of CRLEntries using the array of CERTCrlEntries pointed to
+ * by "nssCrlEntries" and stores it at "pCrlEntryList". If "nssCrlEntries" is
+ * NULL, this function stores an empty List at "pCrlEntryList".
+ * }
+ * PARAMETERS:
+ * "nssCrlEntries"
+ * Address of array of CERTCrlEntries representing NSS CRL entries.
+ * Can be NULL if CRL has no NSS CRL entries.
+ * "pCrlEntryList"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CRLEntry Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_CRLEntry_Create(
+ CERTCrlEntry **nssCrlEntries, /* head of entry list */
+ PKIX_List **pCrlEntryList,
+ void *plContext)
+{
+ PKIX_List *entryList = NULL;
+ PKIX_PL_CRLEntry *crlEntry = NULL;
+ CERTCrlEntry **entries = NULL;
+ SECItem serialNumberItem;
+ PKIX_PL_BigInt *serialNumber;
+ char *bytes = NULL;
+ PKIX_UInt32 length;
+
+ PKIX_ENTER(CRLENTRY, "pkix_pl_CRLEntry_Create");
+ PKIX_NULLCHECK_ONE(pCrlEntryList);
+
+ entries = nssCrlEntries;
+
+ PKIX_CHECK(PKIX_List_Create(&entryList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ if (entries) {
+ while (*entries){
+ PKIX_CHECK(pkix_pl_CRLEntry_CreateEntry
+ (*entries, &crlEntry, plContext),
+ PKIX_COULDNOTCREATECRLENTRYOBJECT);
+
+ /* Get Serial Number */
+ serialNumberItem = (*entries)->serialNumber;
+ length = serialNumberItem.len;
+ bytes = (char *)serialNumberItem.data;
+
+ PKIX_CHECK(pkix_pl_BigInt_CreateWithBytes
+ (bytes, length, &serialNumber, plContext),
+ PKIX_BIGINTCREATEWITHBYTESFAILED);
+
+ crlEntry->serialNumber = serialNumber;
+ crlEntry->nssCrlEntry = *entries;
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (entryList, (PKIX_PL_Object *)crlEntry, plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(crlEntry);
+
+ entries++;
+ }
+ }
+
+ *pCrlEntryList = entryList;
+
+cleanup:
+ PKIX_DECREF(crlEntry);
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(entryList);
+ }
+
+ PKIX_RETURN(CRLENTRY);
+}
+
+/* --Public-CRLENTRY-Functions------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_CRLEntry_GetCRLEntryReasonCode
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_CRLEntry_GetCRLEntryReasonCode (
+ PKIX_PL_CRLEntry *crlEntry,
+ PKIX_Int32 *pReason,
+ void *plContext)
+{
+ SECStatus status;
+ CERTCRLEntryReasonCode nssReasonCode;
+
+ PKIX_ENTER(CRLENTRY, "PKIX_PL_CRLEntry_GetCRLEntryReasonCode");
+ PKIX_NULLCHECK_TWO(crlEntry, pReason);
+
+ if (!crlEntry->userReasonCodeAbsent && crlEntry->userReasonCode == 0) {
+
+ PKIX_OBJECT_LOCK(crlEntry);
+
+ if (!crlEntry->userReasonCodeAbsent &&
+ crlEntry->userReasonCode == 0) {
+
+ /* reason code has not been cached in */
+ PKIX_CRLENTRY_DEBUG("\t\tCERT_FindCRLEntryReasonExten.\n");
+ status = CERT_FindCRLEntryReasonExten
+ (crlEntry->nssCrlEntry, &nssReasonCode);
+
+ if (status == SECSuccess) {
+ crlEntry->userReasonCode = (PKIX_Int32) nssReasonCode;
+ } else {
+ crlEntry->userReasonCodeAbsent = PKIX_TRUE;
+ }
+ }
+
+ PKIX_OBJECT_UNLOCK(crlEntry);
+
+ }
+
+ *pReason = crlEntry->userReasonCode;
+
+cleanup:
+
+ PKIX_RETURN(CRLENTRY);
+}
+
+/*
+ * FUNCTION: PKIX_PL_CRLEntry_GetCriticalExtensionOIDs
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_CRLEntry_GetCriticalExtensionOIDs (
+ PKIX_PL_CRLEntry *crlEntry,
+ PKIX_List **pList, /* list of PKIX_PL_OID */
+ void *plContext)
+{
+ PKIX_List *oidsList = NULL;
+ CERTCertExtension **extensions;
+
+ PKIX_ENTER(CRLENTRY, "PKIX_PL_CRLEntry_GetCriticalExtensionOIDs");
+ PKIX_NULLCHECK_THREE(crlEntry, crlEntry->nssCrlEntry, pList);
+
+ /* if we don't have a cached copy from before, we create one */
+ if (crlEntry->critExtOids == NULL) {
+
+ PKIX_OBJECT_LOCK(crlEntry);
+
+ if (crlEntry->critExtOids == NULL) {
+
+ extensions = crlEntry->nssCrlEntry->extensions;
+
+ PKIX_CHECK(pkix_pl_OID_GetCriticalExtensionOIDs
+ (extensions, &oidsList, plContext),
+ PKIX_GETCRITICALEXTENSIONOIDSFAILED);
+
+ crlEntry->critExtOids = oidsList;
+ }
+
+ PKIX_OBJECT_UNLOCK(crlEntry);
+
+ }
+
+ /* We should return a copy of the List since this list changes */
+ PKIX_DUPLICATE(crlEntry->critExtOids, pList, plContext,
+ PKIX_OBJECTDUPLICATELISTFAILED);
+
+cleanup:
+
+ PKIX_RETURN(CRLENTRY);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.h
new file mode 100644
index 000000000..9cdb6bc92
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_crlentry.h
@@ -0,0 +1,46 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_crlentry.h
+ *
+ * CRL Entry Type Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_CRLENTRY_H
+#define _PKIX_PL_CRLENTRY_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define PKIX_PL_CRL_REASONCODE_NOTSET (-1)
+
+struct PKIX_PL_CRLEntryStruct {
+ CERTCrlEntry *nssCrlEntry;
+ PKIX_PL_BigInt *serialNumber;
+ PKIX_List *critExtOids;
+ PKIX_Int32 userReasonCode;
+ PKIX_Boolean userReasonCodeAbsent;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_CRLEntry_RegisterSelf(void *plContext);
+
+/* following functions are called by CRL only hence not public */
+
+PKIX_Error *
+pkix_pl_CRLEntry_Create(
+ CERTCrlEntry **nssCrlEntry, /* head of entry list */
+ PKIX_List **pCrlEntryList,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_CRLENTRY_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.c
new file mode 100644
index 000000000..4b5016bd0
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.c
@@ -0,0 +1,466 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_date.c
+ *
+ * Date Object Definitions
+ *
+ */
+
+#include "pkix_pl_date.h"
+
+/* --Private-Date-Functions------------------------------------- */
+/*
+ * FUNCTION: pkix_pl_Date_GetPRTime
+ * DESCRIPTION:
+ *
+ * Translates into a PRTime the Date embodied by the Date object pointed to
+ * by "date", and stores it at "pPRTime".
+ *
+ * PARAMETERS
+ * "date"
+ * Address of Date whose PRTime representation is desired. Must be
+ * non-NULL.
+ * "pPRTime"
+ * Address where PRTime value will be stored. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Date Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Date_GetPRTime(
+ PKIX_PL_Date *date,
+ PRTime *pPRTime,
+ void *plContext)
+{
+ PKIX_ENTER(DATE, "PKIX_PL_Date_GetPRTime");
+ PKIX_NULLCHECK_TWO(date, pPRTime);
+
+ *pPRTime = date->nssTime;
+
+ PKIX_RETURN(DATE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Date_CreateFromPRTime
+ * DESCRIPTION:
+ *
+ * Creates a new Date from the PRTime whose value is "prtime", and stores the
+ * result at "pDate".
+ *
+ * PARAMETERS
+ * "prtime"
+ * The PRTime value to be embodied in the new Date object.
+ * "pDate"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Date Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Date_CreateFromPRTime(
+ PRTime prtime,
+ PKIX_PL_Date **pDate,
+ void *plContext)
+{
+ PKIX_PL_Date *date = NULL;
+
+ PKIX_ENTER(DATE, "PKIX_PL_Date_CreateFromPRTime");
+ PKIX_NULLCHECK_ONE(pDate);
+
+ /* create a PKIX_PL_Date object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_DATE_TYPE,
+ sizeof (PKIX_PL_Date),
+ (PKIX_PL_Object **)&date,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+ /* populate the nssTime field */
+ date->nssTime = prtime;
+ *pDate = date;
+cleanup:
+ PKIX_RETURN(DATE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Date_ToString_Helper
+ * DESCRIPTION:
+ *
+ * Helper function that creates a string representation of the SECItem pointed
+ * to by "nssTime" (which represents a date) and stores it at "pString".
+ *
+ * PARAMETERS
+ * "nssTime"
+ * Address of SECItem whose string representation is desired.
+ * Must be non-NULL.
+ * "pString"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Date Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Date_ToString_Helper(
+ SECItem *nssTime,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ char *asciiDate = NULL;
+
+ PKIX_ENTER(DATE, "pkix_pl_Date_ToString_Helper");
+ PKIX_NULLCHECK_TWO(nssTime, pString);
+
+ switch (nssTime->type) {
+ case siUTCTime:
+ PKIX_PL_NSSCALLRV
+ (DATE, asciiDate, DER_UTCDayToAscii, (nssTime));
+ if (!asciiDate){
+ PKIX_ERROR(PKIX_DERUTCTIMETOASCIIFAILED);
+ }
+ break;
+ case siGeneralizedTime:
+ /*
+ * we don't currently have any way to create GeneralizedTime.
+ * this code is only here so that it will be in place when
+ * we do have the capability to create GeneralizedTime.
+ */
+ PKIX_PL_NSSCALLRV
+ (DATE, asciiDate, DER_GeneralizedDayToAscii, (nssTime));
+ if (!asciiDate){
+ PKIX_ERROR(PKIX_DERGENERALIZEDDAYTOASCIIFAILED);
+ }
+ break;
+ default:
+ PKIX_ERROR(PKIX_UNRECOGNIZEDTIMETYPE);
+ }
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, asciiDate, 0, pString, plContext),
+ PKIX_STRINGCREATEFAILED);
+
+cleanup:
+ PR_Free(asciiDate);
+
+ PKIX_RETURN(DATE);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_Date_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Date_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_ENTER(DATE, "pkix_pl_Date_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_DATE_TYPE, plContext),
+ PKIX_OBJECTNOTDATE);
+cleanup:
+ PKIX_RETURN(DATE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Date_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Date_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_Date *date = NULL;
+ SECItem nssTime = {siBuffer, NULL, 0};
+ SECStatus rv;
+
+ PKIX_ENTER(DATE, "pkix_pl_Date_toString");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_DATE_TYPE, plContext),
+ PKIX_OBJECTNOTDATE);
+
+ date = (PKIX_PL_Date *)object;
+ rv = DER_EncodeTimeChoice(NULL, &nssTime, date->nssTime);
+ if (rv == SECFailure) {
+ PKIX_ERROR(PKIX_DERENCODETIMECHOICEFAILED);
+ }
+ PKIX_CHECK(pkix_pl_Date_ToString_Helper
+ (&nssTime, pString, plContext),
+ PKIX_DATETOSTRINGHELPERFAILED);
+cleanup:
+ if (nssTime.data) {
+ SECITEM_FreeItem(&nssTime, PR_FALSE);
+ }
+
+ PKIX_RETURN(DATE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Date_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Date_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_Date *date = NULL;
+ PKIX_UInt32 dateHash;
+
+ PKIX_ENTER(DATE, "pkix_pl_Date_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_DATE_TYPE, plContext),
+ PKIX_OBJECTNOTDATE);
+
+ date = (PKIX_PL_Date *)object;
+
+ PKIX_CHECK(pkix_hash
+ ((const unsigned char *)&date->nssTime,
+ sizeof(date->nssTime),
+ &dateHash,
+ plContext),
+ PKIX_HASHFAILED);
+
+ *pHashcode = dateHash;
+
+cleanup:
+
+ PKIX_RETURN(DATE);
+
+}
+
+/*
+ * FUNCTION: pkix_pl_Date_Comparator
+ * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Date_Comparator(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Int32 *pResult,
+ void *plContext)
+{
+ PRTime firstTime;
+ PRTime secondTime;
+ SECComparison cmpResult;
+
+ PKIX_ENTER(DATE, "pkix_pl_Date_Comparator");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ PKIX_CHECK(pkix_CheckTypes
+ (firstObject, secondObject, PKIX_DATE_TYPE, plContext),
+ PKIX_ARGUMENTSNOTDATES);
+
+ firstTime = ((PKIX_PL_Date *)firstObject)->nssTime;
+ secondTime = ((PKIX_PL_Date *)secondObject)->nssTime;
+
+ if (firstTime == secondTime)
+ cmpResult = SECEqual;
+ else if (firstTime < secondTime)
+ cmpResult = SECLessThan;
+ else
+ cmpResult = SECGreaterThan;
+
+ *pResult = cmpResult;
+
+cleanup:
+
+ PKIX_RETURN(DATE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Date_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Date_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_ENTER(DATE, "pkix_pl_Date_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ /* test that firstObject is a Date */
+ PKIX_CHECK(pkix_CheckType(firstObject, PKIX_DATE_TYPE, plContext),
+ PKIX_FIRSTOBJECTNOTDATE);
+
+ /*
+ * Since we know firstObject is a Date, if both references are
+ * identical, they must be equal
+ */
+ if (firstObject == secondObject){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ *pResult = PKIX_FALSE;
+ pkixErrorResult =
+ pkix_pl_Date_Comparator(firstObject, secondObject,
+ pResult, plContext);
+ if (pkixErrorResult) {
+ PKIX_DECREF(pkixErrorResult);
+ }
+
+cleanup:
+
+ PKIX_RETURN(DATE);
+}
+
+/*
+ * FUNCTION: pkix_pl_Date_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_DATE_TYPE and its related functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_Date_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry* entry = &systemClasses[PKIX_DATE_TYPE];
+
+ PKIX_ENTER(CRLCHECKER, "pkix_CrlDp_RegisterSelf");
+
+ entry->description = "Date";
+ entry->typeObjectSize = sizeof(PKIX_PL_Date);
+ entry->destructor = pkix_pl_Date_Destroy;
+ entry->equalsFunction = pkix_pl_Date_Equals;
+ entry->hashcodeFunction = pkix_pl_Date_Hashcode;
+ entry->toStringFunction = pkix_pl_Date_ToString;
+ entry->comparator = pkix_pl_Date_Comparator;
+ entry->duplicateFunction = pkix_duplicateImmutable;
+
+ PKIX_RETURN(DATE);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_Date_Create_UTCTime (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Date_Create_UTCTime(
+ PKIX_PL_String *stringRep,
+ PKIX_PL_Date **pDate,
+ void *plContext)
+{
+ PKIX_PL_Date *date = NULL;
+ char *asciiString = NULL;
+ PKIX_UInt32 escAsciiLength;
+ SECStatus rv;
+ PRTime time;
+
+ PKIX_ENTER(DATE, "PKIX_PL_Date_Create_UTCTime");
+ PKIX_NULLCHECK_ONE(pDate);
+
+ if (stringRep == NULL){
+ PKIX_DATE_DEBUG("\t\tCalling PR_Now).\n");
+ time = PR_Now();
+ } else {
+ /* convert the input PKIX_PL_String to PKIX_ESCASCII */
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ (stringRep,
+ PKIX_ESCASCII,
+ (void **)&asciiString,
+ &escAsciiLength,
+ plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+
+ PKIX_DATE_DEBUG("\t\tCalling DER_AsciiToTime).\n");
+ /* DER_AsciiToTime only supports UTCTime (2-digit years) */
+ rv = DER_AsciiToTime(&time, asciiString);
+ if (rv != SECSuccess){
+ PKIX_ERROR(PKIX_DERASCIITOTIMEFAILED);
+ }
+ }
+
+ /* create a PKIX_PL_Date object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_DATE_TYPE,
+ sizeof (PKIX_PL_Date),
+ (PKIX_PL_Object **)&date,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ /* populate the nssTime field */
+ date->nssTime = time;
+ *pDate = date;
+
+cleanup:
+ PKIX_FREE(asciiString);
+
+ PKIX_RETURN(DATE);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Date_Create_CurrentOffBySeconds
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_Date_Create_CurrentOffBySeconds(
+ PKIX_Int32 secondsOffset,
+ PKIX_PL_Date **pDate,
+ void *plContext)
+{
+ PKIX_PL_Date *date = NULL;
+ PRTime time;
+
+ PKIX_ENTER(DATE, "PKIX_PL_Date_Create_CurrentOffBySeconds");
+ PKIX_NULLCHECK_ONE(pDate);
+
+ time = PR_Now() + PR_SecondsToInterval(secondsOffset);
+ /* create a PKIX_PL_Date object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_DATE_TYPE,
+ sizeof (PKIX_PL_Date),
+ (PKIX_PL_Object **)&date,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ /* populate the nssTime field */
+ date->nssTime = time;
+ *pDate = date;
+
+cleanup:
+ PKIX_RETURN(DATE);
+}
+
+PKIX_Error *
+PKIX_PL_Date_CreateFromPRTime(
+ PRTime prtime,
+ PKIX_PL_Date **pDate,
+ void *plContext)
+{
+ PKIX_ENTER(DATE, "PKIX_PL_Date_CreateFromPRTime");
+ PKIX_CHECK(
+ pkix_pl_Date_CreateFromPRTime(prtime, pDate, plContext),
+ PKIX_DATECREATEFROMPRTIMEFAILED);
+
+cleanup:
+ PKIX_RETURN(DATE);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.h
new file mode 100644
index 000000000..415597580
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_date.h
@@ -0,0 +1,55 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_date.h
+ *
+ * Date Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_DATE_H
+#define _PKIX_PL_DATE_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_DateStruct{
+ PRTime nssTime;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_Date_ToString_Helper(
+ SECItem *nssTime,
+ PKIX_PL_String **pString,
+ void *plContext);
+
+PKIX_Error *pkix_pl_Date_RegisterSelf(void *plContext);
+
+PKIX_Error *
+pkix_pl_Date_GetPRTime(
+ PKIX_PL_Date *date,
+ PRTime *pPRTime,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_Date_CreateFromPRTime(
+ PRTime prtime,
+ PKIX_PL_Date **pDate,
+ void *plContext);
+
+PKIX_Error *
+PKIX_PL_Date_CreateFromPRTime(
+ PRTime prtime,
+ PKIX_PL_Date **pDate,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_DATE_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.c
new file mode 100644
index 000000000..9e9a74c78
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.c
@@ -0,0 +1,873 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_generalname.c
+ *
+ * GeneralName Object Definitions
+ *
+ */
+
+#include "pkix_pl_generalname.h"
+
+/* --Private-GeneralName-Functions------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_GeneralName_GetNssGeneralName
+ * DESCRIPTION:
+ *
+ * Retrieves the NSS representation of the PKIX_PL_GeneralName pointed by
+ * "genName" and stores it at "pNssGenName". The NSS data type CERTGeneralName
+ * is stored in this object when the object was created.
+ *
+ * PARAMETERS:
+ * "genName"
+ * Address of PKIX_PL_GeneralName. Must be non-NULL.
+ * "pNssGenName"
+ * Address where CERTGeneralName will be stored. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a GeneralName Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_GeneralName_GetNssGeneralName(
+ PKIX_PL_GeneralName *genName,
+ CERTGeneralName **pNssGenName,
+ void *plContext)
+{
+ CERTGeneralName *nssGenName = NULL;
+
+ PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_GetNssGeneralName");
+ PKIX_NULLCHECK_THREE(genName, pNssGenName, genName->nssGeneralNameList);
+
+ nssGenName = genName->nssGeneralNameList->name;
+
+ *pNssGenName = nssGenName;
+
+ PKIX_RETURN(GENERALNAME);
+}
+
+/*
+ * FUNCTION: pkix_pl_OtherName_Create
+ * DESCRIPTION:
+ *
+ * Creates new OtherName which represents the CERTGeneralName pointed to by
+ * "nssAltName" and stores it at "pOtherName".
+ *
+ * PARAMETERS:
+ * "nssAltName"
+ * Address of CERTGeneralName. Must be non-NULL.
+ * "pOtherName"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a GeneralName Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_OtherName_Create(
+ CERTGeneralName *nssAltName,
+ OtherName **pOtherName,
+ void *plContext)
+{
+ OtherName *otherName = NULL;
+ SECItem secItemName;
+ SECItem secItemOID;
+ SECStatus rv;
+
+ PKIX_ENTER(GENERALNAME, "pkix_pl_OtherName_Create");
+ PKIX_NULLCHECK_TWO(nssAltName, pOtherName);
+
+ PKIX_CHECK(PKIX_PL_Malloc
+ (sizeof (OtherName), (void **)&otherName, plContext),
+ PKIX_MALLOCFAILED);
+
+ /* make a copy of the name field */
+ PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_CopyItem).\n");
+ rv = SECITEM_CopyItem
+ (NULL, &otherName->name, &nssAltName->name.OthName.name);
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ /* make a copy of the oid field */
+ PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_CopyItem).\n");
+ rv = SECITEM_CopyItem
+ (NULL, &otherName->oid, &nssAltName->name.OthName.oid);
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ *pOtherName = otherName;
+
+cleanup:
+
+ if (otherName && PKIX_ERROR_RECEIVED){
+ secItemName = otherName->name;
+ secItemOID = otherName->oid;
+
+ PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n");
+ SECITEM_FreeItem(&secItemName, PR_FALSE);
+
+ PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n");
+ SECITEM_FreeItem(&secItemOID, PR_FALSE);
+
+ PKIX_FREE(otherName);
+ otherName = NULL;
+ }
+
+ PKIX_RETURN(GENERALNAME);
+}
+
+/*
+ * FUNCTION: pkix_pl_DirectoryName_Create
+ * DESCRIPTION:
+ *
+ * Creates a new X500Name which represents the directoryName component of the
+ * CERTGeneralName pointed to by "nssAltName" and stores it at "pX500Name".
+ *
+ * PARAMETERS:
+ * "nssAltName"
+ * Address of CERTGeneralName. Must be non-NULL.
+ * "pX500Name"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a GeneralName Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_DirectoryName_Create(
+ CERTGeneralName *nssAltName,
+ PKIX_PL_X500Name **pX500Name,
+ void *plContext)
+{
+ PKIX_PL_X500Name *pkixDN = NULL;
+ CERTName *dirName = NULL;
+ PKIX_PL_String *pkixDNString = NULL;
+ char *utf8String = NULL;
+
+ PKIX_ENTER(GENERALNAME, "pkix_pl_DirectoryName_Create");
+ PKIX_NULLCHECK_TWO(nssAltName, pX500Name);
+
+ dirName = &nssAltName->name.directoryName;
+
+ PKIX_CHECK(PKIX_PL_X500Name_CreateFromCERTName(NULL, dirName,
+ &pkixDN, plContext),
+ PKIX_X500NAMECREATEFROMCERTNAMEFAILED);
+
+ *pX500Name = pkixDN;
+
+cleanup:
+
+ PR_Free(utf8String);
+ PKIX_DECREF(pkixDNString);
+
+ PKIX_RETURN(GENERALNAME);
+}
+
+/*
+ * FUNCTION: pkix_pl_GeneralName_Create
+ * DESCRIPTION:
+ *
+ * Creates new GeneralName which represents the CERTGeneralName pointed to by
+ * "nssAltName" and stores it at "pGenName".
+ *
+ * PARAMETERS:
+ * "nssAltName"
+ * Address of CERTGeneralName. Must be non-NULL.
+ * "pGenName"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a GeneralName Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_GeneralName_Create(
+ CERTGeneralName *nssAltName,
+ PKIX_PL_GeneralName **pGenName,
+ void *plContext)
+{
+ PKIX_PL_GeneralName *genName = NULL;
+ PKIX_PL_X500Name *pkixDN = NULL;
+ PKIX_PL_OID *pkixOID = NULL;
+ OtherName *otherName = NULL;
+ CERTGeneralNameList *nssGenNameList = NULL;
+ CERTGeneralNameType nameType;
+
+ PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_Create");
+ PKIX_NULLCHECK_TWO(nssAltName, pGenName);
+
+ /* create a PKIX_PL_GeneralName object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_GENERALNAME_TYPE,
+ sizeof (PKIX_PL_GeneralName),
+ (PKIX_PL_Object **)&genName,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ nameType = nssAltName->type;
+
+ /*
+ * We use CERT_CreateGeneralNameList to create just one CERTGeneralName
+ * item for memory allocation reason. If we want to just create one
+ * item, we have to use the calling path CERT_NewGeneralName, then
+ * CERT_CopyOneGeneralName. With this calling path, if we pass
+ * the arena argument as NULL, in CERT_CopyOneGeneralName's subsequent
+ * call to CERT_CopyName, it assumes arena should be valid, hence
+ * segmentation error (not sure this is a NSS bug, certainly it is
+ * not consistent). But on the other hand, we don't want to keep an
+ * arena record here explicitely for every PKIX_PL_GeneralName.
+ * So I concluded it is better to use CERT_CreateGeneralNameList,
+ * which keeps an arena pointer in its data structure and also masks
+ * out details calls from this libpkix level.
+ */
+
+ PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_CreateGeneralNameList).\n");
+ nssGenNameList = CERT_CreateGeneralNameList(nssAltName);
+
+ if (nssGenNameList == NULL) {
+ PKIX_ERROR(PKIX_CERTCREATEGENERALNAMELISTFAILED);
+ }
+
+ genName->nssGeneralNameList = nssGenNameList;
+
+ /* initialize fields */
+ genName->type = nameType;
+ genName->directoryName = NULL;
+ genName->OthName = NULL;
+ genName->other = NULL;
+ genName->oid = NULL;
+
+ switch (nameType){
+ case certOtherName:
+
+ PKIX_CHECK(pkix_pl_OtherName_Create
+ (nssAltName, &otherName, plContext),
+ PKIX_OTHERNAMECREATEFAILED);
+
+ genName->OthName = otherName;
+ break;
+
+ case certDirectoryName:
+
+ PKIX_CHECK(pkix_pl_DirectoryName_Create
+ (nssAltName, &pkixDN, plContext),
+ PKIX_DIRECTORYNAMECREATEFAILED);
+
+ genName->directoryName = pkixDN;
+ break;
+ case certRegisterID:
+ PKIX_CHECK(PKIX_PL_OID_CreateBySECItem(&nssAltName->name.other,
+ &pkixOID, plContext),
+ PKIX_OIDCREATEFAILED);
+
+ genName->oid = pkixOID;
+ break;
+ case certDNSName:
+ case certEDIPartyName:
+ case certIPAddress:
+ case certRFC822Name:
+ case certX400Address:
+ case certURI:
+ genName->other = SECITEM_DupItem(&nssAltName->name.other);
+ if (!genName->other) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+ break;
+ default:
+ PKIX_ERROR(PKIX_NAMETYPENOTSUPPORTED);
+ }
+
+ *pGenName = genName;
+ genName = NULL;
+
+cleanup:
+ PKIX_DECREF(genName);
+
+ PKIX_RETURN(GENERALNAME);
+}
+
+/*
+ * FUNCTION: pkix_pl_GeneralName_ToString_Helper
+ * DESCRIPTION:
+ *
+ * Helper function that creates a string representation of the GeneralName
+ * pointed to by "name" and stores it at "pString" Different mechanisms are
+ * used to create the string, depending on the type of the GeneralName.
+ *
+ * PARAMETERS
+ * "name"
+ * Address of GeneralName whose string representation is desired.
+ * Must be non-NULL.
+ * "pString"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a GeneralName Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_GeneralName_ToString_Helper(
+ PKIX_PL_GeneralName *name,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_X500Name *pkixDN = NULL;
+ PKIX_PL_OID *pkixOID = NULL;
+ char *x400AsciiName = NULL;
+ char *ediPartyName = NULL;
+ char *asciiName = NULL;
+
+ PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_ToString_Helper");
+ PKIX_NULLCHECK_TWO(name, pString);
+
+ switch (name->type) {
+ case certRFC822Name:
+ case certDNSName:
+ case certURI:
+ /*
+ * Note that we can't use PKIX_ESCASCII here because
+ * name->other->data is not guaranteed to be null-terminated.
+ */
+
+ PKIX_NULLCHECK_ONE(name->other);
+
+ PKIX_CHECK(PKIX_PL_String_Create(PKIX_UTF8,
+ (name->other)->data,
+ (name->other)->len,
+ pString,
+ plContext),
+ PKIX_STRINGCREATEFAILED);
+ break;
+ case certEDIPartyName:
+ /* XXX print out the actual bytes */
+ ediPartyName = "EDIPartyName: <DER-encoded value>";
+ PKIX_CHECK(PKIX_PL_String_Create(PKIX_ESCASCII,
+ ediPartyName,
+ 0,
+ pString,
+ plContext),
+ PKIX_STRINGCREATEFAILED);
+ break;
+ case certX400Address:
+ /* XXX print out the actual bytes */
+ x400AsciiName = "X400Address: <DER-encoded value>";
+ PKIX_CHECK(PKIX_PL_String_Create(PKIX_ESCASCII,
+ x400AsciiName,
+ 0,
+ pString,
+ plContext),
+ PKIX_STRINGCREATEFAILED);
+ break;
+ case certIPAddress:
+ PKIX_CHECK(pkix_pl_ipAddrBytes2Ascii
+ (name->other, &asciiName, plContext),
+ PKIX_IPADDRBYTES2ASCIIFAILED);
+
+ PKIX_CHECK(PKIX_PL_String_Create(PKIX_ESCASCII,
+ asciiName,
+ 0,
+ pString,
+ plContext),
+ PKIX_STRINGCREATEFAILED);
+ break;
+ case certOtherName:
+ PKIX_NULLCHECK_ONE(name->OthName);
+
+ /* we only print type-id - don't know how to print value */
+ /* XXX print out the bytes of the value */
+ PKIX_CHECK(pkix_pl_oidBytes2Ascii
+ (&name->OthName->oid, &asciiName, plContext),
+ PKIX_OIDBYTES2ASCIIFAILED);
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII,
+ asciiName,
+ 0,
+ pString,
+ plContext),
+ PKIX_STRINGCREATEFAILED);
+ break;
+ case certRegisterID:
+ pkixOID = name->oid;
+ PKIX_CHECK(PKIX_PL_Object_ToString
+ ((PKIX_PL_Object *)pkixOID, pString, plContext),
+ PKIX_OIDTOSTRINGFAILED);
+ break;
+ case certDirectoryName:
+ pkixDN = name->directoryName;
+ PKIX_CHECK(PKIX_PL_Object_ToString
+ ((PKIX_PL_Object *)pkixDN, pString, plContext),
+ PKIX_X500NAMETOSTRINGFAILED);
+ break;
+ default:
+ PKIX_ERROR
+ (PKIX_TOSTRINGFORTHISGENERALNAMETYPENOTSUPPORTED);
+ }
+
+cleanup:
+
+ PKIX_FREE(asciiName);
+
+ PKIX_RETURN(GENERALNAME);
+}
+
+/*
+ * FUNCTION: pkix_pl_GeneralName_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_GeneralName_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_GeneralName *name = NULL;
+ SECItem secItemName;
+ SECItem secItemOID;
+
+ PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_GENERALNAME_TYPE, plContext),
+ PKIX_OBJECTNOTGENERALNAME);
+
+ name = (PKIX_PL_GeneralName *)object;
+
+ PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n");
+ SECITEM_FreeItem(name->other, PR_TRUE);
+ name->other = NULL;
+
+ if (name->OthName){
+ secItemName = name->OthName->name;
+ secItemOID = name->OthName->oid;
+
+ PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n");
+ SECITEM_FreeItem(&secItemName, PR_FALSE);
+
+ PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n");
+ SECITEM_FreeItem(&secItemOID, PR_FALSE);
+
+ PKIX_FREE(name->OthName);
+ name->OthName = NULL;
+ }
+
+ if (name->nssGeneralNameList != NULL) {
+ PKIX_GENERALNAME_DEBUG
+ ("\t\tCalling CERT_DestroyGeneralNameList).\n");
+ CERT_DestroyGeneralNameList(name->nssGeneralNameList);
+ }
+
+ PKIX_DECREF(name->directoryName);
+ PKIX_DECREF(name->oid);
+
+cleanup:
+
+ PKIX_RETURN(GENERALNAME);
+}
+
+/*
+ * FUNCTION: pkix_pl_GeneralName_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_GeneralName_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_String *nameString = NULL;
+ PKIX_PL_GeneralName *name = NULL;
+
+ PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_toString");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_GENERALNAME_TYPE, plContext),
+ PKIX_OBJECTNOTGENERALNAME);
+
+ name = (PKIX_PL_GeneralName *)object;
+
+ PKIX_CHECK(pkix_pl_GeneralName_ToString_Helper
+ (name, &nameString, plContext),
+ PKIX_GENERALNAMETOSTRINGHELPERFAILED);
+
+ *pString = nameString;
+
+cleanup:
+
+
+
+ PKIX_RETURN(GENERALNAME);
+}
+
+/*
+ * FUNCTION: pkix_pl_GeneralName_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_GeneralName_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_GeneralName *name = NULL;
+ PKIX_UInt32 firstHash, secondHash, nameHash;
+
+ PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_GENERALNAME_TYPE, plContext),
+ PKIX_OBJECTNOTGENERALNAME);
+
+ name = (PKIX_PL_GeneralName *)object;
+
+ switch (name->type) {
+ case certRFC822Name:
+ case certDNSName:
+ case certX400Address:
+ case certEDIPartyName:
+ case certURI:
+ case certIPAddress:
+ PKIX_NULLCHECK_ONE(name->other);
+ PKIX_CHECK(pkix_hash
+ ((const unsigned char *)
+ name->other->data,
+ name->other->len,
+ &nameHash,
+ plContext),
+ PKIX_HASHFAILED);
+ break;
+ case certRegisterID:
+ PKIX_CHECK(PKIX_PL_Object_Hashcode
+ ((PKIX_PL_Object *)name->oid,
+ &nameHash,
+ plContext),
+ PKIX_OIDHASHCODEFAILED);
+ break;
+ case certOtherName:
+ PKIX_NULLCHECK_ONE(name->OthName);
+ PKIX_CHECK(pkix_hash
+ ((const unsigned char *)
+ name->OthName->oid.data,
+ name->OthName->oid.len,
+ &firstHash,
+ plContext),
+ PKIX_HASHFAILED);
+
+ PKIX_CHECK(pkix_hash
+ ((const unsigned char *)
+ name->OthName->name.data,
+ name->OthName->name.len,
+ &secondHash,
+ plContext),
+ PKIX_HASHFAILED);
+
+ nameHash = firstHash + secondHash;
+ break;
+ case certDirectoryName:
+ PKIX_CHECK(PKIX_PL_Object_Hashcode
+ ((PKIX_PL_Object *)
+ name->directoryName,
+ &nameHash,
+ plContext),
+ PKIX_X500NAMEHASHCODEFAILED);
+ break;
+ }
+
+ *pHashcode = nameHash;
+
+cleanup:
+
+ PKIX_RETURN(GENERALNAME);
+
+}
+
+/*
+ * FUNCTION: pkix_pl_GeneralName_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_GeneralName_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_PL_GeneralName *firstName = NULL;
+ PKIX_PL_GeneralName *secondName = NULL;
+ PKIX_UInt32 secondType;
+
+ PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ /* test that firstObject is a GeneralName */
+ PKIX_CHECK(pkix_CheckType
+ (firstObject, PKIX_GENERALNAME_TYPE, plContext),
+ PKIX_FIRSTOBJECTNOTGENERALNAME);
+
+ /*
+ * Since we know firstObject is a GeneralName, if both references are
+ * identical, they must be equal
+ */
+ if (firstObject == secondObject){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondObject isn't a GeneralName, we don't throw an error.
+ * We simply return a Boolean result of FALSE
+ */
+ *pResult = PKIX_FALSE;
+ PKIX_CHECK(PKIX_PL_Object_GetType
+ (secondObject, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+ if (secondType != PKIX_GENERALNAME_TYPE){
+ goto cleanup;
+ }
+
+ firstName = (PKIX_PL_GeneralName *)firstObject;
+ secondName = (PKIX_PL_GeneralName *)secondObject;
+
+ if (firstName->type != secondName->type){
+ goto cleanup;
+ }
+
+ switch (firstName->type) {
+ case certRFC822Name:
+ case certDNSName:
+ case certX400Address:
+ case certEDIPartyName:
+ case certURI:
+ case certIPAddress:
+ PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_CompareItem).\n");
+ if (SECITEM_CompareItem(firstName->other,
+ secondName->other) != SECEqual) {
+ goto cleanup;
+ }
+ break;
+ case certRegisterID:
+ PKIX_CHECK(PKIX_PL_Object_Equals
+ ((PKIX_PL_Object *)firstName->oid,
+ (PKIX_PL_Object *)secondName->oid,
+ pResult,
+ plContext),
+ PKIX_OIDEQUALSFAILED);
+ goto cleanup;
+ case certOtherName:
+ PKIX_NULLCHECK_TWO(firstName->OthName, secondName->OthName);
+ PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_CompareItem).\n");
+ if (SECITEM_CompareItem(&firstName->OthName->oid,
+ &secondName->OthName->oid)
+ != SECEqual ||
+ SECITEM_CompareItem(&firstName->OthName->name,
+ &secondName->OthName->name)
+ != SECEqual) {
+ goto cleanup;
+ }
+ break;
+ case certDirectoryName:
+ PKIX_CHECK(PKIX_PL_Object_Equals
+ ((PKIX_PL_Object *)firstName->directoryName,
+ (PKIX_PL_Object *)secondName->directoryName,
+ pResult,
+ plContext),
+ PKIX_X500NAMEEQUALSFAILED);
+ goto cleanup;
+ }
+
+ *pResult = PKIX_TRUE;
+
+cleanup:
+
+ PKIX_RETURN(GENERALNAME);
+}
+
+/*
+ * FUNCTION: pkix_pl_GeneralName_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_GENERALNAME_TYPE and related functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_GeneralName_RegisterSelf(void *plContext)
+{
+
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(GENERALNAME, "pkix_pl_GeneralName_RegisterSelf");
+
+ entry.description = "GeneralName";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_GeneralName);
+ entry.destructor = pkix_pl_GeneralName_Destroy;
+ entry.equalsFunction = pkix_pl_GeneralName_Equals;
+ entry.hashcodeFunction = pkix_pl_GeneralName_Hashcode;
+ entry.toStringFunction = pkix_pl_GeneralName_ToString;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_GENERALNAME_TYPE] = entry;
+
+ PKIX_RETURN(GENERALNAME);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+#ifdef BUILD_LIBPKIX_TESTS
+/*
+ * FUNCTION: PKIX_PL_GeneralName_Create (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_GeneralName_Create(
+ PKIX_UInt32 nameType,
+ PKIX_PL_String *stringRep,
+ PKIX_PL_GeneralName **pGName,
+ void *plContext)
+{
+ PKIX_PL_X500Name *pkixDN = NULL;
+ PKIX_PL_OID *pkixOID = NULL;
+ SECItem *secItem = NULL;
+ char *asciiString = NULL;
+ PKIX_UInt32 length = 0;
+ PKIX_PL_GeneralName *genName = NULL;
+ CERTGeneralName *nssGenName = NULL;
+ CERTGeneralNameList *nssGenNameList = NULL;
+ CERTName *nssCertName = NULL;
+ PLArenaPool *arena = NULL;
+
+ PKIX_ENTER(GENERALNAME, "PKIX_PL_GeneralName_Create");
+ PKIX_NULLCHECK_TWO(pGName, stringRep);
+
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ (stringRep,
+ PKIX_ESCASCII,
+ (void **)&asciiString,
+ &length,
+ plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+
+ /* Create a temporary CERTGeneralName */
+ PKIX_GENERALNAME_DEBUG("\t\tCalling PL_strlen).\n");
+ length = PL_strlen(asciiString);
+ PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_AllocItem).\n");
+ secItem = SECITEM_AllocItem(NULL, NULL, length);
+ PKIX_GENERALNAME_DEBUG("\t\tCalling PORT_Memcpy).\n");
+ (void) PORT_Memcpy(secItem->data, asciiString, length);
+ PKIX_CERT_DEBUG("\t\tCalling PORT_NewArena).\n");
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+ PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_NewGeneralName).\n");
+ nssGenName = CERT_NewGeneralName(arena, nameType);
+ if (nssGenName == NULL) {
+ PKIX_ERROR(PKIX_ALLOCATENEWCERTGENERALNAMEFAILED);
+ }
+
+ switch (nameType) {
+ case certRFC822Name:
+ case certDNSName:
+ case certURI:
+ nssGenName->name.other = *secItem;
+ break;
+
+ case certDirectoryName:
+
+ PKIX_CHECK(PKIX_PL_X500Name_Create
+ (stringRep, &pkixDN, plContext),
+ PKIX_X500NAMECREATEFAILED);
+
+ PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_AsciiToName).\n");
+ nssCertName = CERT_AsciiToName(asciiString);
+ nssGenName->name.directoryName = *nssCertName;
+ break;
+
+ case certRegisterID:
+ PKIX_CHECK(PKIX_PL_OID_Create
+ (asciiString, &pkixOID, plContext),
+ PKIX_OIDCREATEFAILED);
+ nssGenName->name.other = *secItem;
+ break;
+ default:
+ /* including IPAddress, EDIPartyName, OtherName, X400Address */
+ PKIX_ERROR(PKIX_UNABLETOCREATEGENERALNAMEOFTHISTYPE);
+ }
+
+ /* create a PKIX_PL_GeneralName object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_GENERALNAME_TYPE,
+ sizeof (PKIX_PL_GeneralName),
+ (PKIX_PL_Object **)&genName,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ /* create a CERTGeneralNameList */
+ nssGenName->type = nameType;
+ PKIX_GENERALNAME_DEBUG("\t\tCalling CERT_CreateGeneralNameList).\n");
+ nssGenNameList = CERT_CreateGeneralNameList(nssGenName);
+ if (nssGenNameList == NULL) {
+ PKIX_ERROR(PKIX_CERTCREATEGENERALNAMELISTFAILED);
+ }
+ genName->nssGeneralNameList = nssGenNameList;
+
+ /* initialize fields */
+ genName->type = nameType;
+ genName->directoryName = pkixDN;
+ genName->OthName = NULL;
+ genName->other = secItem;
+ genName->oid = pkixOID;
+
+ *pGName = genName;
+cleanup:
+
+ PKIX_FREE(asciiString);
+
+ if (nssCertName != NULL) {
+ PKIX_CERT_DEBUG("\t\tCalling CERT_DestroyName).\n");
+ CERT_DestroyName(nssCertName);
+ }
+
+ if (arena){ /* will free nssGenName */
+ PKIX_CERT_DEBUG("\t\tCalling PORT_FreeArena).\n");
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(pkixDN);
+ PKIX_DECREF(pkixOID);
+
+ PKIX_GENERALNAME_DEBUG("\t\tCalling SECITEM_FreeItem).\n");
+ if (secItem){
+ SECITEM_FreeItem(secItem, PR_TRUE);
+ secItem = NULL;
+ }
+ }
+
+ PKIX_RETURN(GENERALNAME);
+}
+
+#endif /* BUILD_LIBPKIX_TESTS */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.h
new file mode 100644
index 000000000..3cb5264d5
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_generalname.h
@@ -0,0 +1,49 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_generalname.h
+ *
+ * GeneralName Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_GENERALNAME_H
+#define _PKIX_PL_GENERALNAME_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_GeneralNameStruct{
+ CERTGeneralNameList *nssGeneralNameList;
+ CERTGeneralNameType type;
+ PKIX_PL_X500Name *directoryName;
+ PKIX_PL_OID *oid;
+ OtherName *OthName;
+ SECItem *other;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_pl_GeneralName_Create(
+ CERTGeneralName *nssAltName,
+ PKIX_PL_GeneralName **pGenName,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_GeneralName_GetNssGeneralName(
+ PKIX_PL_GeneralName *genName,
+ CERTGeneralName **pNssGenName,
+ void *plContext);
+
+PKIX_Error *pkix_pl_GeneralName_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_GENERALNAME_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.c
new file mode 100644
index 000000000..9fa8e9260
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.c
@@ -0,0 +1,874 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_infoaccess.c
+ *
+ * InfoAccess Object Definitions
+ *
+ */
+
+#include "pkix_pl_infoaccess.h"
+
+/* --Private-InfoAccess-Functions----------------------------------*/
+
+/*
+ * FUNCTION: pkix_pl_InfoAccess_Create
+ * DESCRIPTION:
+ *
+ * This function creates an InfoAccess from the method provided in "method" and
+ * the GeneralName provided in "generalName" and stores the result at
+ * "pInfoAccess".
+ *
+ * PARAMETERS
+ * "method"
+ * The UInt32 value to be stored as the method field of the InfoAccess.
+ * "generalName"
+ * The GeneralName to be stored as the generalName field of the InfoAccess.
+ * Must be non-NULL.
+ * "pInfoAccess"
+ * Address where the result is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_InfoAccess_Create(
+ PKIX_UInt32 method,
+ PKIX_PL_GeneralName *generalName,
+ PKIX_PL_InfoAccess **pInfoAccess,
+ void *plContext)
+{
+
+ PKIX_PL_InfoAccess *infoAccess = NULL;
+
+ PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Create");
+ PKIX_NULLCHECK_TWO(generalName, pInfoAccess);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_INFOACCESS_TYPE,
+ sizeof (PKIX_PL_InfoAccess),
+ (PKIX_PL_Object **)&infoAccess,
+ plContext),
+ PKIX_COULDNOTCREATEINFOACCESSOBJECT);
+
+ infoAccess->method = method;
+
+ PKIX_INCREF(generalName);
+ infoAccess->location = generalName;
+
+ *pInfoAccess = infoAccess;
+ infoAccess = NULL;
+
+cleanup:
+ PKIX_DECREF(infoAccess);
+
+ PKIX_RETURN(INFOACCESS);
+}
+
+/*
+ * FUNCTION: pkix_pl_InfoAccess_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_pki.h)
+ */
+static PKIX_Error *
+pkix_pl_InfoAccess_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_InfoAccess *infoAccess = NULL;
+
+ PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_INFOACCESS_TYPE, plContext),
+ PKIX_OBJECTNOTANINFOACCESS);
+
+ infoAccess = (PKIX_PL_InfoAccess *)object;
+
+ PKIX_DECREF(infoAccess->location);
+
+cleanup:
+
+ PKIX_RETURN(INFOACCESS);
+}
+
+/*
+ * FUNCTION: pkix_pl_InfoAccess_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_pki.h)
+ */
+static PKIX_Error *
+pkix_pl_InfoAccess_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_InfoAccess *infoAccess;
+ PKIX_PL_String *infoAccessString = NULL;
+ char *asciiFormat = NULL;
+ char *asciiMethod = NULL;
+ PKIX_PL_String *formatString = NULL;
+ PKIX_PL_String *methodString = NULL;
+ PKIX_PL_String *locationString = NULL;
+
+ PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ToString");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_INFOACCESS_TYPE, plContext),
+ PKIX_OBJECTNOTINFOACCESS);
+
+ infoAccess = (PKIX_PL_InfoAccess *)object;
+
+ asciiFormat =
+ "["
+ "method:%s, "
+ "location:%s"
+ "]";
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII,
+ asciiFormat,
+ 0,
+ &formatString,
+ plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ switch(infoAccess->method) {
+ case PKIX_INFOACCESS_CA_ISSUERS:
+ asciiMethod = "caIssuers";
+ break;
+ case PKIX_INFOACCESS_OCSP:
+ asciiMethod = "ocsp";
+ break;
+ case PKIX_INFOACCESS_TIMESTAMPING:
+ asciiMethod = "timestamping";
+ break;
+ case PKIX_INFOACCESS_CA_REPOSITORY:
+ asciiMethod = "caRepository";
+ break;
+ default:
+ asciiMethod = "unknown";
+ }
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII,
+ asciiMethod,
+ 0,
+ &methodString,
+ plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ PKIX_TOSTRING(infoAccess->location, &locationString, plContext,
+ PKIX_GENERALNAMETOSTRINGFAILED);
+
+ PKIX_CHECK(PKIX_PL_Sprintf
+ (&infoAccessString,
+ plContext,
+ formatString,
+ methodString,
+ locationString),
+ PKIX_SPRINTFFAILED);
+
+ *pString = infoAccessString;
+
+cleanup:
+
+ PKIX_DECREF(formatString);
+ PKIX_DECREF(methodString);
+ PKIX_DECREF(locationString);
+
+ PKIX_RETURN(INFOACCESS);
+}
+
+/*
+ * FUNCTION: pkix_pl_InfoAccess_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_pki.h)
+ */
+static PKIX_Error *
+pkix_pl_InfoAccess_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_InfoAccess *infoAccess = NULL;
+ PKIX_UInt32 infoAccessHash;
+
+ PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_INFOACCESS_TYPE, plContext),
+ PKIX_OBJECTNOTINFOACCESS);
+
+ infoAccess = (PKIX_PL_InfoAccess *)object;
+
+ PKIX_HASHCODE(infoAccess->location, &infoAccessHash, plContext,
+ PKIX_OBJECTHASHCODEFAILED);
+
+ infoAccessHash += (infoAccess->method << 7);
+
+ *pHashcode = infoAccessHash;
+
+cleanup:
+
+ PKIX_RETURN(INFOACCESS);
+
+}
+
+/*
+ * FUNCTION: pkix_pl_InfoAccess_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_pki.h)
+ */
+static PKIX_Error *
+pkix_pl_InfoAccess_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_PL_InfoAccess *firstInfoAccess = NULL;
+ PKIX_PL_InfoAccess *secondInfoAccess = NULL;
+ PKIX_UInt32 secondType;
+ PKIX_Boolean cmpResult;
+
+ PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ /* test that firstObject is a InfoAccess */
+ PKIX_CHECK(pkix_CheckType
+ (firstObject, PKIX_INFOACCESS_TYPE, plContext),
+ PKIX_FIRSTOBJECTNOTINFOACCESS);
+
+ /*
+ * Since we know firstObject is a InfoAccess, if both references are
+ * identical, they must be equal
+ */
+ if (firstObject == secondObject){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondObject isn't a InfoAccess, we don't throw an error.
+ * We simply return a Boolean result of FALSE
+ */
+ *pResult = PKIX_FALSE;
+ PKIX_CHECK(PKIX_PL_Object_GetType
+ (secondObject, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+ if (secondType != PKIX_INFOACCESS_TYPE) goto cleanup;
+
+ firstInfoAccess = (PKIX_PL_InfoAccess *)firstObject;
+ secondInfoAccess = (PKIX_PL_InfoAccess *)secondObject;
+
+ *pResult = PKIX_FALSE;
+
+ if (firstInfoAccess->method != secondInfoAccess->method) {
+ goto cleanup;
+ }
+
+ PKIX_EQUALS(firstInfoAccess, secondInfoAccess, &cmpResult, plContext,
+ PKIX_OBJECTEQUALSFAILED);
+
+ *pResult = cmpResult;
+
+cleanup:
+
+ PKIX_RETURN(INFOACCESS);
+}
+
+/*
+ * FUNCTION: pkix_pl_InfoAccess_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_INFOACCESS_TYPE and its related functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_InfoAccess_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(INFOACCESS,
+ "pkix_pl_InfoAccess_RegisterSelf");
+
+ entry.description = "InfoAccess";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_InfoAccess);
+ entry.destructor = pkix_pl_InfoAccess_Destroy;
+ entry.equalsFunction = pkix_pl_InfoAccess_Equals;
+ entry.hashcodeFunction = pkix_pl_InfoAccess_Hashcode;
+ entry.toStringFunction = pkix_pl_InfoAccess_ToString;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_INFOACCESS_TYPE] = entry;
+
+ PKIX_RETURN(INFOACCESS);
+}
+
+/*
+ * FUNCTION: pkix_pl_InfoAccess_CreateList
+ * DESCRIPTION:
+ *
+ * Based on data in CERTAuthInfoAccess array "nssInfoAccess", this function
+ * creates and returns a PKIX_List of PKIX_PL_InfoAccess at "pInfoAccessList".
+ *
+ * PARAMETERS
+ * "nssInfoAccess"
+ * The pointer array of CERTAuthInfoAccess that contains access data.
+ * May be NULL.
+ * "pInfoAccessList"
+ * Address where a list of PKIX_PL_InfoAccess is returned.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_InfoAccess_CreateList(
+ CERTAuthInfoAccess **nssInfoAccess,
+ PKIX_List **pInfoAccessList, /* of PKIX_PL_InfoAccess */
+ void *plContext)
+{
+ PKIX_List *infoAccessList = NULL;
+ PKIX_PL_InfoAccess *infoAccess = NULL;
+ PKIX_PL_GeneralName *location = NULL;
+ PKIX_UInt32 method;
+ int i;
+
+ PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_CreateList");
+ PKIX_NULLCHECK_ONE(pInfoAccessList);
+
+ PKIX_CHECK(PKIX_List_Create(&infoAccessList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ if (nssInfoAccess == NULL) {
+ goto cleanup;
+ }
+
+ for (i = 0; nssInfoAccess[i] != NULL; i++) {
+
+ if (nssInfoAccess[i]->location == NULL) {
+ continue;
+ }
+
+ PKIX_CHECK(pkix_pl_GeneralName_Create
+ (nssInfoAccess[i]->location, &location, plContext),
+ PKIX_GENERALNAMECREATEFAILED);
+
+ PKIX_CERT_DEBUG("\t\tCalling SECOID_FindOIDTag).\n");
+ method = SECOID_FindOIDTag(&nssInfoAccess[i]->method);
+ /* Map NSS access method value into PKIX constant */
+ switch(method) {
+ case SEC_OID_PKIX_CA_ISSUERS:
+ method = PKIX_INFOACCESS_CA_ISSUERS;
+ break;
+ case SEC_OID_PKIX_OCSP:
+ method = PKIX_INFOACCESS_OCSP;
+ break;
+ case SEC_OID_PKIX_TIMESTAMPING:
+ method = PKIX_INFOACCESS_TIMESTAMPING;
+ break;
+ case SEC_OID_PKIX_CA_REPOSITORY:
+ method = PKIX_INFOACCESS_CA_REPOSITORY;
+ break;
+ default:
+ PKIX_ERROR(PKIX_UNKNOWNINFOACCESSMETHOD);
+ }
+
+ PKIX_CHECK(pkix_pl_InfoAccess_Create
+ (method, location, &infoAccess, plContext),
+ PKIX_INFOACCESSCREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (infoAccessList,
+ (PKIX_PL_Object *)infoAccess,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ PKIX_DECREF(infoAccess);
+ PKIX_DECREF(location);
+ }
+
+ *pInfoAccessList = infoAccessList;
+ infoAccessList = NULL;
+
+cleanup:
+
+ PKIX_DECREF(infoAccessList);
+ PKIX_DECREF(infoAccess);
+ PKIX_DECREF(location);
+
+ PKIX_RETURN(INFOACCESS);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_InfoAccess_GetMethod (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_InfoAccess_GetMethod(
+ PKIX_PL_InfoAccess *infoAccess,
+ PKIX_UInt32 *pMethod,
+ void *plContext)
+{
+ PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetMethod");
+ PKIX_NULLCHECK_TWO(infoAccess, pMethod);
+
+ *pMethod = infoAccess->method;
+
+ PKIX_RETURN(INFOACCESS);
+}
+
+/*
+ * FUNCTION: PKIX_PL_InfoAccess_GetLocation (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_InfoAccess_GetLocation(
+ PKIX_PL_InfoAccess *infoAccess,
+ PKIX_PL_GeneralName **pLocation,
+ void *plContext)
+{
+ PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetLocation");
+ PKIX_NULLCHECK_TWO(infoAccess, pLocation);
+
+ PKIX_INCREF(infoAccess->location);
+
+ *pLocation = infoAccess->location;
+
+cleanup:
+ PKIX_RETURN(INFOACCESS);
+}
+
+/*
+ * FUNCTION: PKIX_PL_InfoAccess_GetLocationType (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_InfoAccess_GetLocationType(
+ PKIX_PL_InfoAccess *infoAccess,
+ PKIX_UInt32 *pType,
+ void *plContext)
+{
+ PKIX_PL_String *locationString = NULL;
+ PKIX_UInt32 type = PKIX_INFOACCESS_LOCATION_UNKNOWN;
+ PKIX_UInt32 len = 0;
+ void *location = NULL;
+
+ PKIX_ENTER(INFOACCESS, "PKIX_PL_InfoAccess_GetLocationType");
+ PKIX_NULLCHECK_TWO(infoAccess, pType);
+
+ if (infoAccess->location != NULL) {
+
+ PKIX_TOSTRING(infoAccess->location, &locationString, plContext,
+ PKIX_GENERALNAMETOSTRINGFAILED);
+
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ (locationString, PKIX_ESCASCII, &location, &len, plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+
+ PKIX_OID_DEBUG("\tCalling PORT_Strcmp).\n");
+#ifndef NSS_PKIX_NO_LDAP
+ if (PORT_Strncmp(location, "ldap:", 5) == 0){
+ type = PKIX_INFOACCESS_LOCATION_LDAP;
+ } else
+#endif
+ if (PORT_Strncmp(location, "http:", 5) == 0){
+ type = PKIX_INFOACCESS_LOCATION_HTTP;
+ }
+ }
+
+ *pType = type;
+
+cleanup:
+
+ PKIX_PL_Free(location, plContext);
+ PKIX_DECREF(locationString);
+
+ PKIX_RETURN(INFOACCESS);
+}
+
+#ifndef NSS_PKIX_NO_LDAP
+/*
+ * FUNCTION: pkix_pl_InfoAccess_ParseTokens
+ * DESCRIPTION:
+ *
+ * This function parses the string beginning at "startPos" into tokens using
+ * the separator contained in "separator" and the terminator contained in
+ * "terminator", copying the tokens into space allocated from the arena
+ * pointed to by "arena". It stores in "tokens" a null-terminated array of
+ * pointers to those tokens.
+ *
+ * PARAMETERS
+ * "arena"
+ * Address of a PLArenaPool to be used in populating the LDAPLocation.
+ * Must be non-NULL.
+ * "startPos"
+ * The address of char string that contains a subset of ldap location.
+ * "tokens"
+ * The address of an array of char string for storing returned tokens.
+ * Must be non-NULL.
+ * "separator"
+ * The character that is taken as token separator. Must be non-NULL.
+ * "terminator"
+ * The character that is taken as parsing terminator. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an InfoAccess Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_InfoAccess_ParseTokens(
+ PLArenaPool *arena,
+ char **startPos, /* return update */
+ char ***tokens,
+ char separator,
+ char terminator,
+ void *plContext)
+{
+ PKIX_UInt32 numFilters = 0;
+ char *endPos = NULL;
+ char **filterP = NULL;
+
+ PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ParseTokens");
+ PKIX_NULLCHECK_THREE(arena, startPos, tokens);
+
+ endPos = *startPos;
+
+ /* First pass: parse to <terminator> to count number of components */
+ numFilters = 0;
+ while (*endPos != terminator && *endPos != '\0') {
+ endPos++;
+ if (*endPos == separator) {
+ numFilters++;
+ }
+ }
+
+ if (*endPos != terminator) {
+ PKIX_ERROR(PKIX_LOCATIONSTRINGNOTPROPERLYTERMINATED);
+ }
+
+ /* Last component doesn't need a separator, although we allow it */
+ if (endPos > *startPos && *(endPos-1) != separator) {
+ numFilters++;
+ }
+
+ /*
+ * If string is a=xx, b=yy, c=zz, etc., use a=xx for filter,
+ * and everything else for the base
+ */
+ if (numFilters > 2) numFilters = 2;
+
+ filterP = PORT_ArenaZNewArray(arena, char*, numFilters+1);
+ if (filterP == NULL) {
+ PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
+ }
+
+ /* Second pass: parse to fill in components in token array */
+ *tokens = filterP;
+ endPos = *startPos;
+
+ while (numFilters) {
+ if (*endPos == separator || *endPos == terminator) {
+ PKIX_UInt32 len = endPos - *startPos;
+ char *p = PORT_ArenaZAlloc(arena, len+1);
+ if (p == NULL) {
+ PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
+ }
+
+ PORT_Memcpy(p, *startPos, len);
+ p[len] = '\0';
+
+ *filterP = p;
+ filterP++;
+ numFilters--;
+
+ separator = terminator;
+
+ if (*endPos == '\0') {
+ *startPos = endPos;
+ break;
+ } else {
+ endPos++;
+ *startPos = endPos;
+ continue;
+ }
+ }
+ endPos++;
+ }
+
+ *filterP = NULL;
+
+cleanup:
+
+ PKIX_RETURN(INFOACCESS);
+}
+
+static int
+pkix_pl_HexDigitToInt(
+ int ch)
+{
+ if (isdigit(ch)) {
+ ch = ch - '0';
+ } else if (isupper(ch)) {
+ ch = ch - 'A' + 10;
+ } else {
+ ch = ch - 'a' + 10;
+ }
+ return ch;
+}
+
+/*
+ * Convert the "%" hex hex escape sequences in the URL 'location' in place.
+ */
+static void
+pkix_pl_UnescapeURL(
+ char *location)
+{
+ const char *src;
+ char *dst;
+
+ for (src = dst = location; *src != '\0'; src++, dst++) {
+ if (*src == '%' && isxdigit((unsigned char)*(src+1)) &&
+ isxdigit((unsigned char)*(src+2))) {
+ *dst = pkix_pl_HexDigitToInt((unsigned char)*(src+1));
+ *dst *= 16;
+ *dst += pkix_pl_HexDigitToInt((unsigned char)*(src+2));
+ src += 2;
+ } else {
+ *dst = *src;
+ }
+ }
+ *dst = *src; /* the terminating null */
+}
+
+/*
+ * FUNCTION: pkix_pl_InfoAccess_ParseLocation
+ * DESCRIPTION:
+ *
+ * This function parses the GeneralName pointed to by "generalName" into the
+ * fields of the LDAPRequestParams pointed to by "request" and a domainName
+ * pointed to by "pDomainName", using the PLArenaPool pointed to by "arena" to
+ * allocate storage for the request components and for the domainName string.
+ *
+ * The expected GeneralName string should be in the format described by the
+ * following BNF:
+ *
+ * ldap://<ldap-server-site>/[cn=<cname>][,o=<org>][,c=<country>]?
+ * [caCertificate|crossCertificatPair|certificateRevocationList];
+ * [binary|<other-type>]
+ * [[,caCertificate|crossCertificatPair|certificateRevocationList]
+ * [binary|<other-type>]]*
+ *
+ * PARAMETERS
+ * "generalName"
+ * Address of the GeneralName whose LDAPLocation is to be parsed. Must be
+ * non-NULL.
+ * "arena"
+ * Address of PLArenaPool to be used for the domainName and for components
+ * of the LDAPRequest. Must be non-NULL.
+ * "request"
+ * Address of the LDAPRequestParams into which request components are
+ * stored. Must be non-NULL.
+ * *pDomainName"
+ * Address at which the domainName is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an InfoAccess Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_InfoAccess_ParseLocation(
+ PKIX_PL_GeneralName *generalName,
+ PLArenaPool *arena,
+ LDAPRequestParams *request,
+ char **pDomainName,
+ void *plContext)
+{
+ PKIX_PL_String *locationString = NULL;
+ PKIX_UInt32 len = 0;
+ PKIX_UInt32 ncIndex = 0;
+ char *domainName = NULL;
+ char **avaArray = NULL;
+ char **attrArray = NULL;
+ char *attr = NULL;
+ char *locationAscii = NULL;
+ char *startPos = NULL;
+ char *endPos = NULL;
+ char *avaPtr = NULL;
+ LdapAttrMask attrBit = 0;
+ LDAPNameComponent **setOfNameComponent = NULL;
+ LDAPNameComponent *nameComponent = NULL;
+
+ PKIX_ENTER(INFOACCESS, "pkix_pl_InfoAccess_ParseLocation");
+ PKIX_NULLCHECK_FOUR(generalName, arena, request, pDomainName);
+
+ PKIX_TOSTRING(generalName, &locationString, plContext,
+ PKIX_GENERALNAMETOSTRINGFAILED);
+
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ (locationString,
+ PKIX_ESCASCII,
+ (void **)&locationAscii,
+ &len,
+ plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+
+ pkix_pl_UnescapeURL(locationAscii);
+
+ /* Skip "ldap:" */
+ endPos = locationAscii;
+ while (*endPos != ':' && *endPos != '\0') {
+ endPos++;
+ }
+ if (*endPos == '\0') {
+ PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGLOCATIONTYPE);
+ }
+
+ /* Skip "//" */
+ endPos++;
+ if (*endPos != '\0' && *(endPos+1) != '0' &&
+ *endPos == '/' && *(endPos+1) == '/') {
+ endPos += 2;
+ } else {
+ PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGDOUBLESLASH);
+ }
+
+ /* Get the server-site */
+ startPos = endPos;
+ while(*endPos != '/' && *(endPos) != '\0') {
+ endPos++;
+ }
+ if (*endPos == '\0') {
+ PKIX_ERROR(PKIX_GENERALNAMESTRINGMISSINGSERVERSITE);
+ }
+
+ len = endPos - startPos;
+ endPos++;
+
+ domainName = PORT_ArenaZAlloc(arena, len + 1);
+ if (!domainName) {
+ PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
+ }
+
+ PORT_Memcpy(domainName, startPos, len);
+
+ domainName[len] = '\0';
+
+ *pDomainName = domainName;
+
+ /*
+ * Get a list of AttrValueAssertions (such as
+ * "cn=CommonName, o=Organization, c=US" into a null-terminated array
+ */
+ startPos = endPos;
+ PKIX_CHECK(pkix_pl_InfoAccess_ParseTokens
+ (arena,
+ &startPos,
+ (char ***) &avaArray,
+ ',',
+ '?',
+ plContext),
+ PKIX_INFOACCESSPARSETOKENSFAILED);
+
+ /* Count how many AVAs we have */
+ for (len = 0; avaArray[len] != NULL; len++) {}
+
+ if (len < 2) {
+ PKIX_ERROR(PKIX_NOTENOUGHNAMECOMPONENTSINGENERALNAME);
+ }
+
+ /* Use last name component for baseObject */
+ request->baseObject = avaArray[len - 1];
+
+ /* Use only one component for filter. LDAP servers aren't too smart. */
+ len = 2; /* Eliminate this when servers get smarter. */
+
+ avaArray[len - 1] = NULL;
+
+ /* Get room for null-terminated array of (LdapNameComponent *) */
+ setOfNameComponent = PORT_ArenaZNewArray(arena, LDAPNameComponent *, len);
+ if (setOfNameComponent == NULL) {
+ PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
+ }
+
+ /* Get room for the remaining LdapNameComponents */
+ nameComponent = PORT_ArenaZNewArray(arena, LDAPNameComponent, --len);
+ if (nameComponent == NULL) {
+ PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
+ }
+
+ /* Convert remaining AVAs to LDAPNameComponents */
+ for (ncIndex = 0; ncIndex < len; ncIndex ++) {
+ setOfNameComponent[ncIndex] = nameComponent;
+ avaPtr = avaArray[ncIndex];
+ nameComponent->attrType = (unsigned char *)avaPtr;
+ while ((*avaPtr != '=') && (*avaPtr != '\0')) {
+ avaPtr++;
+ if (*avaPtr == '\0') {
+ PKIX_ERROR(PKIX_NAMECOMPONENTWITHNOEQ);
+ }
+ }
+ *(avaPtr++) = '\0';
+ nameComponent->attrValue = (unsigned char *)avaPtr;
+ nameComponent++;
+ }
+
+ setOfNameComponent[len] = NULL;
+ request->nc = setOfNameComponent;
+
+ /*
+ * Get a list of AttrTypes (such as
+ * "caCertificate;binary, crossCertificatePair;binary") into
+ * a null-terminated array
+ */
+
+ PKIX_CHECK(pkix_pl_InfoAccess_ParseTokens
+ (arena,
+ (char **) &startPos,
+ (char ***) &attrArray,
+ ',',
+ '\0',
+ plContext),
+ PKIX_INFOACCESSPARSETOKENSFAILED);
+
+ /* Convert array of Attr Types into a bit mask */
+ request->attributes = 0;
+ attr = attrArray[0];
+ while (attr != NULL) {
+ PKIX_CHECK(pkix_pl_LdapRequest_AttrStringToBit
+ (attr, &attrBit, plContext),
+ PKIX_LDAPREQUESTATTRSTRINGTOBITFAILED);
+ request->attributes |= attrBit;
+ attr = *(++attrArray);
+ }
+
+cleanup:
+
+ PKIX_PL_Free(locationAscii, plContext);
+ PKIX_DECREF(locationString);
+
+ PKIX_RETURN(INFOACCESS);
+}
+#endif /* !NSS_PKIX_NO_LDAP */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.h
new file mode 100644
index 000000000..e69d7b413
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_infoaccess.h
@@ -0,0 +1,49 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_infoaccess.h
+ *
+ * InfoAccess Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_INFOACCESS_H
+#define _PKIX_PL_INFOACCESS_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_InfoAccessStruct{
+ PKIX_UInt32 method;
+ PKIX_PL_GeneralName *location;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_InfoAccess_RegisterSelf(void *plContext);
+
+PKIX_Error *
+pkix_pl_InfoAccess_CreateList(
+ CERTAuthInfoAccess **authInfoAccess,
+ PKIX_List **pAiaList, /* of PKIX_PL_InfoAccess */
+ void *plContext);
+
+#ifndef NSS_PKIX_NO_LDAP
+PKIX_Error *
+pkix_pl_InfoAccess_ParseLocation(
+ PKIX_PL_GeneralName *generalName,
+ PLArenaPool *arena,
+ LDAPRequestParams *request,
+ char **pDomainName,
+ void *plContext);
+#endif /* !NSS_PKIX_NO_LDAP */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_INFOACCESS_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.c
new file mode 100644
index 000000000..affea8741
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.c
@@ -0,0 +1,1274 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_nameconstraints.c
+ *
+ * Name Constraints Object Functions Definitions
+ *
+ */
+
+#include "pkix_pl_nameconstraints.h"
+
+
+/* --Private-NameConstraints-Functions----------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_CertNameConstraints_GetPermitted
+ * DESCRIPTION:
+ *
+ * This function retrieve name constraints permitted list from NSS
+ * data in "nameConstraints" and returns a PKIX_PL_GeneralName list
+ * in "pPermittedList".
+ *
+ * PARAMETERS
+ * "nameConstraints"
+ * Address of CertNameConstraints which has a pointer to
+ * CERTNameConstraints data. Must be non-NULL.
+ * "pPermittedList"
+ * Address where returned permitted name list is stored. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Conditionally Thread Safe
+ * (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a NameConstraints Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CertNameConstraints_GetPermitted(
+ PKIX_PL_CertNameConstraints *nameConstraints,
+ PKIX_List **pPermittedList,
+ void *plContext)
+{
+ CERTNameConstraints *nssNameConstraints = NULL;
+ CERTNameConstraints **nssNameConstraintsList = NULL;
+ CERTNameConstraint *nssPermitted = NULL;
+ CERTNameConstraint *firstPermitted = NULL;
+ PKIX_List *permittedList = NULL;
+ PKIX_PL_GeneralName *name = NULL;
+ PKIX_UInt32 numItems = 0;
+ PKIX_UInt32 i;
+
+ PKIX_ENTER(CERTNAMECONSTRAINTS,
+ "pkix_pl_CertNameConstraints_GetPermitted");
+ PKIX_NULLCHECK_TWO(nameConstraints, pPermittedList);
+
+ /*
+ * nssNameConstraints is an array of CERTNameConstraints
+ * pointers where CERTNameConstraints keep its permitted and excluded
+ * lists as pointer array of CERTNameConstraint.
+ */
+
+ if (nameConstraints->permittedList == NULL) {
+
+ PKIX_OBJECT_LOCK(nameConstraints);
+
+ if (nameConstraints->permittedList == NULL) {
+
+ PKIX_CHECK(PKIX_List_Create(&permittedList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ numItems = nameConstraints->numNssNameConstraints;
+ nssNameConstraintsList =
+ nameConstraints->nssNameConstraintsList;
+
+ for (i = 0; i < numItems; i++) {
+
+ PKIX_NULLCHECK_ONE(nssNameConstraintsList);
+ nssNameConstraints = *(nssNameConstraintsList + i);
+ PKIX_NULLCHECK_ONE(nssNameConstraints);
+
+ if (nssNameConstraints->permited != NULL) {
+
+ nssPermitted = nssNameConstraints->permited;
+ firstPermitted = nssPermitted;
+
+ do {
+
+ PKIX_CHECK(pkix_pl_GeneralName_Create
+ (&nssPermitted->name, &name, plContext),
+ PKIX_GENERALNAMECREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (permittedList,
+ (PKIX_PL_Object *)name,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(name);
+
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling CERT_GetNextNameConstraint\n");
+ nssPermitted = CERT_GetNextNameConstraint
+ (nssPermitted);
+
+ } while (nssPermitted != firstPermitted);
+
+ }
+ }
+
+ PKIX_CHECK(PKIX_List_SetImmutable(permittedList, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ nameConstraints->permittedList = permittedList;
+
+ }
+
+ PKIX_OBJECT_UNLOCK(nameConstraints);
+
+ }
+
+ PKIX_INCREF(nameConstraints->permittedList);
+
+ *pPermittedList = nameConstraints->permittedList;
+
+cleanup:
+
+ PKIX_RETURN(CERTNAMECONSTRAINTS);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertNameConstraints_GetExcluded
+ * DESCRIPTION:
+ *
+ * This function retrieve name constraints excluded list from NSS
+ * data in "nameConstraints" and returns a PKIX_PL_GeneralName list
+ * in "pExcludedList".
+ *
+ * PARAMETERS
+ * "nameConstraints"
+ * Address of CertNameConstraints which has a pointer to NSS data.
+ * Must be non-NULL.
+ * "pPermittedList"
+ * Address where returned excluded name list is stored. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Conditionally Thread Safe
+ * (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a NameConstraints Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CertNameConstraints_GetExcluded(
+ PKIX_PL_CertNameConstraints *nameConstraints,
+ PKIX_List **pExcludedList,
+ void *plContext)
+{
+ CERTNameConstraints *nssNameConstraints = NULL;
+ CERTNameConstraints **nssNameConstraintsList = NULL;
+ CERTNameConstraint *nssExcluded = NULL;
+ CERTNameConstraint *firstExcluded = NULL;
+ PKIX_List *excludedList = NULL;
+ PKIX_PL_GeneralName *name = NULL;
+ PKIX_UInt32 numItems = 0;
+ PKIX_UInt32 i;
+
+ PKIX_ENTER(CERTNAMECONSTRAINTS,
+ "pkix_pl_CertNameConstraints_GetExcluded");
+ PKIX_NULLCHECK_TWO(nameConstraints, pExcludedList);
+
+ if (nameConstraints->excludedList == NULL) {
+
+ PKIX_OBJECT_LOCK(nameConstraints);
+
+ if (nameConstraints->excludedList == NULL) {
+
+ PKIX_CHECK(PKIX_List_Create(&excludedList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ numItems = nameConstraints->numNssNameConstraints;
+ nssNameConstraintsList =
+ nameConstraints->nssNameConstraintsList;
+
+ for (i = 0; i < numItems; i++) {
+
+ PKIX_NULLCHECK_ONE(nssNameConstraintsList);
+ nssNameConstraints = *(nssNameConstraintsList + i);
+ PKIX_NULLCHECK_ONE(nssNameConstraints);
+
+ if (nssNameConstraints->excluded != NULL) {
+
+ nssExcluded = nssNameConstraints->excluded;
+ firstExcluded = nssExcluded;
+
+ do {
+
+ PKIX_CHECK(pkix_pl_GeneralName_Create
+ (&nssExcluded->name, &name, plContext),
+ PKIX_GENERALNAMECREATEFAILED);
+
+ PKIX_CHECK(PKIX_List_AppendItem
+ (excludedList,
+ (PKIX_PL_Object *)name,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+
+ PKIX_DECREF(name);
+
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling CERT_GetNextNameConstraint\n");
+ nssExcluded = CERT_GetNextNameConstraint
+ (nssExcluded);
+
+ } while (nssExcluded != firstExcluded);
+
+ }
+
+ }
+ PKIX_CHECK(PKIX_List_SetImmutable(excludedList, plContext),
+ PKIX_LISTSETIMMUTABLEFAILED);
+
+ nameConstraints->excludedList = excludedList;
+
+ }
+
+ PKIX_OBJECT_UNLOCK(nameConstraints);
+ }
+
+ PKIX_INCREF(nameConstraints->excludedList);
+
+ *pExcludedList = nameConstraints->excludedList;
+
+cleanup:
+
+ PKIX_RETURN(CERTNAMECONSTRAINTS);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertNameConstraints_CheckNameSpaceNssNames
+ * DESCRIPTION:
+ *
+ * This function checks if CERTGeneralNames in "nssSubjectNames" comply
+ * with the permitted and excluded names in "nameConstraints". It returns
+ * PKIX_TRUE in "pCheckPass", if the Names satify the name space of the
+ * permitted list and if the Names are not in the excluded list. Otherwise,
+ * it returns PKIX_FALSE.
+ *
+ * PARAMETERS
+ * "nssSubjectNames"
+ * List of CERTGeneralName that nameConstraints verification is based on.
+ * "nameConstraints"
+ * Address of CertNameConstraints that provides lists of permitted
+ * and excluded names. Must be non-NULL.
+ * "pCheckPass"
+ * Address where PKIX_TRUE is returned if the all names in "nameList" are
+ * valid.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a NameConstraints Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_CertNameConstraints_CheckNameSpaceNssNames(
+ CERTGeneralName *nssSubjectNames,
+ PKIX_PL_CertNameConstraints *nameConstraints,
+ PKIX_Boolean *pCheckPass,
+ void *plContext)
+{
+ CERTNameConstraints **nssNameConstraintsList = NULL;
+ CERTNameConstraints *nssNameConstraints = NULL;
+ CERTGeneralName *nssMatchName = NULL;
+ PLArenaPool *arena = NULL;
+ PKIX_UInt32 numItems = 0;
+ PKIX_UInt32 i;
+ SECStatus status = SECSuccess;
+
+ PKIX_ENTER(CERTNAMECONSTRAINTS,
+ "pkix_pl_CertNameConstraints_CheckNameSpaceNssNames");
+ PKIX_NULLCHECK_THREE(nssSubjectNames, nameConstraints, pCheckPass);
+
+ *pCheckPass = PKIX_TRUE;
+
+ PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_NewArena\n");
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ nssMatchName = nssSubjectNames;
+ nssNameConstraintsList = nameConstraints->nssNameConstraintsList;
+
+ /*
+ * CERTNameConstraint items in each permitted or excluded list
+ * is verified as OR condition. That means, if one item matched,
+ * then the checking on the remaining items on the list is skipped.
+ * (see NSS cert_CompareNameWithConstraints(...)).
+ * Items on PKIX_PL_NameConstraint's nssNameConstraints are verified
+ * as AND condition. PKIX_PL_NameConstraint keeps an array of pointers
+ * of CERTNameConstraints resulting from merging multiple
+ * PKIX_PL_NameConstraints. Since each CERTNameConstraint are created
+ * for different entity, a union condition of these entities then is
+ * performed.
+ */
+
+ do {
+
+ numItems = nameConstraints->numNssNameConstraints;
+
+ for (i = 0; i < numItems; i++) {
+
+ PKIX_NULLCHECK_ONE(nssNameConstraintsList);
+ nssNameConstraints = *(nssNameConstraintsList + i);
+ PKIX_NULLCHECK_ONE(nssNameConstraints);
+
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling CERT_CheckNameSpace\n");
+ status = CERT_CheckNameSpace
+ (arena, nssNameConstraints, nssMatchName);
+ if (status != SECSuccess) {
+ break;
+ }
+
+ }
+
+ if (status != SECSuccess) {
+ break;
+ }
+
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling CERT_GetNextGeneralName\n");
+ nssMatchName = CERT_GetNextGeneralName(nssMatchName);
+
+ } while (nssMatchName != nssSubjectNames);
+
+ if (status == SECFailure) {
+
+ *pCheckPass = PKIX_FALSE;
+ }
+
+cleanup:
+
+ if (arena){
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling PORT_FreeArena).\n");
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ PKIX_RETURN(CERTNAMECONSTRAINTS);
+}
+
+/*
+ * FUNCTION: pkix_pl_NameConstraints_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertNameConstraints_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_CertNameConstraints *nameConstraints = NULL;
+
+ PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_CERTNAMECONSTRAINTS_TYPE, plContext),
+ PKIX_OBJECTNOTCERTNAMECONSTRAINTS);
+
+ nameConstraints = (PKIX_PL_CertNameConstraints *)object;
+
+ PKIX_CHECK(PKIX_PL_Free
+ (nameConstraints->nssNameConstraintsList, plContext),
+ PKIX_FREEFAILED);
+
+ if (nameConstraints->arena){
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling PORT_FreeArena).\n");
+ PORT_FreeArena(nameConstraints->arena, PR_FALSE);
+ nameConstraints->arena = NULL;
+ }
+
+ PKIX_DECREF(nameConstraints->permittedList);
+ PKIX_DECREF(nameConstraints->excludedList);
+
+cleanup:
+
+ PKIX_RETURN(CERTNAMECONSTRAINTS);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertNameConstraints_ToString_Helper
+ * DESCRIPTION:
+ *
+ * Helper function that creates a string representation of the object
+ * NameConstraints and stores it at "pString".
+ *
+ * PARAMETERS
+ * "nameConstraints"
+ * Address of CertNameConstraints whose string representation is
+ * desired. Must be non-NULL.
+ * "pString"
+ * Address where string object pointer will be stored. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a NameConstraints Error if the function fails in a
+ * non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CertNameConstraints_ToString_Helper(
+ PKIX_PL_CertNameConstraints *nameConstraints,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ char *asciiFormat = NULL;
+ PKIX_PL_String *formatString = NULL;
+ PKIX_List *permittedList = NULL;
+ PKIX_List *excludedList = NULL;
+ PKIX_PL_String *permittedListString = NULL;
+ PKIX_PL_String *excludedListString = NULL;
+ PKIX_PL_String *nameConstraintsString = NULL;
+
+ PKIX_ENTER(CERTNAMECONSTRAINTS,
+ "pkix_pl_CertNameConstraints_ToString_Helper");
+ PKIX_NULLCHECK_TWO(nameConstraints, pString);
+
+ asciiFormat =
+ "[\n"
+ "\t\tPermitted Name: %s\n"
+ "\t\tExcluded Name: %s\n"
+ "\t]\n";
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII,
+ asciiFormat,
+ 0,
+ &formatString,
+ plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ PKIX_CHECK(pkix_pl_CertNameConstraints_GetPermitted
+ (nameConstraints, &permittedList, plContext),
+ PKIX_CERTNAMECONSTRAINTSGETPERMITTEDFAILED);
+
+ PKIX_TOSTRING(permittedList, &permittedListString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ PKIX_CHECK(pkix_pl_CertNameConstraints_GetExcluded
+ (nameConstraints, &excludedList, plContext),
+ PKIX_CERTNAMECONSTRAINTSGETEXCLUDEDFAILED);
+
+ PKIX_TOSTRING(excludedList, &excludedListString, plContext,
+ PKIX_LISTTOSTRINGFAILED);
+
+ PKIX_CHECK(PKIX_PL_Sprintf
+ (&nameConstraintsString,
+ plContext,
+ formatString,
+ permittedListString,
+ excludedListString),
+ PKIX_SPRINTFFAILED);
+
+ *pString = nameConstraintsString;
+
+cleanup:
+
+ PKIX_DECREF(formatString);
+ PKIX_DECREF(permittedList);
+ PKIX_DECREF(excludedList);
+ PKIX_DECREF(permittedListString);
+ PKIX_DECREF(excludedListString);
+
+ PKIX_RETURN(CERTNAMECONSTRAINTS);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertNameConstraints_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertNameConstraints_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_String *nameConstraintsString = NULL;
+ PKIX_PL_CertNameConstraints *nameConstraints = NULL;
+
+ PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_ToString");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType(
+ object, PKIX_CERTNAMECONSTRAINTS_TYPE, plContext),
+ PKIX_OBJECTNOTCERTNAMECONSTRAINTS);
+
+ nameConstraints = (PKIX_PL_CertNameConstraints *)object;
+
+ PKIX_CHECK(pkix_pl_CertNameConstraints_ToString_Helper
+ (nameConstraints, &nameConstraintsString, plContext),
+ PKIX_CERTNAMECONSTRAINTSTOSTRINGHELPERFAILED);
+
+ *pString = nameConstraintsString;
+
+cleanup:
+
+ PKIX_RETURN(CERTNAMECONSTRAINTS);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertNameConstraints_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertNameConstraints_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_CertNameConstraints *nameConstraints = NULL;
+ PKIX_List *permittedList = NULL;
+ PKIX_List *excludedList = NULL;
+ PKIX_UInt32 permitHash = 0;
+ PKIX_UInt32 excludeHash = 0;
+
+ PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType
+ (object, PKIX_CERTNAMECONSTRAINTS_TYPE, plContext),
+ PKIX_OBJECTNOTCERTNAMECONSTRAINTS);
+
+ nameConstraints = (PKIX_PL_CertNameConstraints *)object;
+
+ PKIX_CHECK(pkix_pl_CertNameConstraints_GetPermitted
+ (nameConstraints, &permittedList, plContext),
+ PKIX_CERTNAMECONSTRAINTSGETPERMITTEDFAILED);
+
+ PKIX_HASHCODE(permittedList, &permitHash, plContext,
+ PKIX_OBJECTHASHCODEFAILED);
+
+ PKIX_CHECK(pkix_pl_CertNameConstraints_GetExcluded
+ (nameConstraints, &excludedList, plContext),
+ PKIX_CERTNAMECONSTRAINTSGETEXCLUDEDFAILED);
+
+ PKIX_HASHCODE(excludedList, &excludeHash, plContext,
+ PKIX_OBJECTHASHCODEFAILED);
+
+ *pHashcode = (((permitHash << 7) + excludeHash) << 7) +
+ nameConstraints->numNssNameConstraints;
+
+cleanup:
+
+ PKIX_DECREF(permittedList);
+ PKIX_DECREF(excludedList);
+ PKIX_RETURN(CERTNAMECONSTRAINTS);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertNameConstraints_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_CertNameConstraints_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_PL_CertNameConstraints *firstNC = NULL;
+ PKIX_PL_CertNameConstraints *secondNC = NULL;
+ PKIX_List *firstPermittedList = NULL;
+ PKIX_List *secondPermittedList = NULL;
+ PKIX_List *firstExcludedList = NULL;
+ PKIX_List *secondExcludedList = NULL;
+ PKIX_UInt32 secondType;
+ PKIX_Boolean cmpResult = PKIX_FALSE;
+
+ PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ /* test that firstObject is a CertNameConstraints */
+ PKIX_CHECK(pkix_CheckType
+ (firstObject, PKIX_CERTNAMECONSTRAINTS_TYPE, plContext),
+ PKIX_FIRSTOBJECTNOTCERTNAMECONSTRAINTS);
+
+ firstNC = (PKIX_PL_CertNameConstraints *)firstObject;
+ secondNC = (PKIX_PL_CertNameConstraints *)secondObject;
+
+ /*
+ * Since we know firstObject is a CertNameConstraints, if both
+ * references are identical, they must be equal
+ */
+ if (firstNC == secondNC){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondNC isn't a CertNameConstraints, we don't throw an error.
+ * We simply return a Boolean result of FALSE
+ */
+ *pResult = PKIX_FALSE;
+
+ PKIX_CHECK(PKIX_PL_Object_GetType
+ ((PKIX_PL_Object *)secondNC, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+
+ if (secondType != PKIX_CERTNAMECONSTRAINTS_TYPE) {
+ goto cleanup;
+ }
+
+ PKIX_CHECK(pkix_pl_CertNameConstraints_GetPermitted
+ (firstNC, &firstPermittedList, plContext),
+ PKIX_CERTNAMECONSTRAINTSGETPERMITTEDFAILED);
+
+ PKIX_CHECK(pkix_pl_CertNameConstraints_GetPermitted
+ (secondNC, &secondPermittedList, plContext),
+ PKIX_CERTNAMECONSTRAINTSGETPERMITTEDFAILED);
+
+ PKIX_EQUALS
+ (firstPermittedList, secondPermittedList, &cmpResult, plContext,
+ PKIX_OBJECTEQUALSFAILED);
+
+ if (cmpResult != PKIX_TRUE) {
+ goto cleanup;
+ }
+
+ PKIX_CHECK(pkix_pl_CertNameConstraints_GetExcluded
+ (firstNC, &firstExcludedList, plContext),
+ PKIX_CERTNAMECONSTRAINTSGETEXCLUDEDFAILED);
+
+ PKIX_CHECK(pkix_pl_CertNameConstraints_GetExcluded
+ (secondNC, &secondExcludedList, plContext),
+ PKIX_CERTNAMECONSTRAINTSGETEXCLUDEDFAILED);
+
+ PKIX_EQUALS
+ (firstExcludedList, secondExcludedList, &cmpResult, plContext,
+ PKIX_OBJECTEQUALSFAILED);
+
+ if (cmpResult != PKIX_TRUE) {
+ goto cleanup;
+ }
+
+ /*
+ * numNssNameConstraints is not checked because it is basically a
+ * merge count, it cannot determine the data equality.
+ */
+
+ *pResult = PKIX_TRUE;
+
+cleanup:
+
+ PKIX_DECREF(firstPermittedList);
+ PKIX_DECREF(secondPermittedList);
+ PKIX_DECREF(firstExcludedList);
+ PKIX_DECREF(secondExcludedList);
+
+ PKIX_RETURN(CERTNAMECONSTRAINTS);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertNameConstraints_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_CERTNAMECONSTRAINTS_TYPE and its related functions with
+ * systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_CertNameConstraints_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(CERTNAMECONSTRAINTS,
+ "pkix_pl_CertNameConstraints_RegisterSelf");
+
+ entry.description = "CertNameConstraints";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_CertNameConstraints);
+ entry.destructor = pkix_pl_CertNameConstraints_Destroy;
+ entry.equalsFunction = pkix_pl_CertNameConstraints_Equals;
+ entry.hashcodeFunction = pkix_pl_CertNameConstraints_Hashcode;
+ entry.toStringFunction = pkix_pl_CertNameConstraints_ToString;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_CERTNAMECONSTRAINTS_TYPE] = entry;
+
+ PKIX_RETURN(CERTNAMECONSTRAINTS);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertNameConstraints_Create_Helper
+ *
+ * DESCRIPTION:
+ * This function retrieves name constraints in "nssNameConstraints",
+ * converts and stores the result in a PKIX_PL_CertNameConstraints object.
+ *
+ * PARAMETERS
+ * "nssNameConstraints"
+ * Address of CERTNameConstraints that contains this object's data.
+ * Must be non-NULL.
+ * "pNameConstraints"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * A NULL value will be returned if there is no Name Constraints extension.
+ * "plContext" - Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a NameConstraints Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CertNameConstraints_Create_Helper(
+ CERTNameConstraints *nssNameConstraints,
+ PKIX_PL_CertNameConstraints **pNameConstraints,
+ void *plContext)
+{
+ PKIX_PL_CertNameConstraints *nameConstraints = NULL;
+ CERTNameConstraints **nssNameConstraintPtr = NULL;
+
+ PKIX_ENTER(CERTNAMECONSTRAINTS,
+ "pkix_pl_CertNameConstraints_Create_Helper");
+ PKIX_NULLCHECK_TWO(nssNameConstraints, pNameConstraints);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_CERTNAMECONSTRAINTS_TYPE,
+ sizeof (PKIX_PL_CertNameConstraints),
+ (PKIX_PL_Object **)&nameConstraints,
+ plContext),
+ PKIX_COULDNOTCREATECERTNAMECONSTRAINTSOBJECT);
+
+ PKIX_CHECK(PKIX_PL_Malloc
+ (sizeof (CERTNameConstraint *),
+ (void *)&nssNameConstraintPtr,
+ plContext),
+ PKIX_MALLOCFAILED);
+
+ nameConstraints->numNssNameConstraints = 1;
+ nameConstraints->nssNameConstraintsList = nssNameConstraintPtr;
+ *nssNameConstraintPtr = nssNameConstraints;
+
+ nameConstraints->permittedList = NULL;
+ nameConstraints->excludedList = NULL;
+ nameConstraints->arena = NULL;
+
+ *pNameConstraints = nameConstraints;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(nameConstraints);
+ }
+
+ PKIX_RETURN(CERTNAMECONSTRAINTS);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertNameConstraints_Create
+ *
+ * DESCRIPTION:
+ * function that allocates and initialize the object CertNameConstraints.
+ *
+ * PARAMETERS
+ * "nssCert"
+ * Address of CERT that contains this object's data.
+ * Must be non-NULL.
+ * "pNameConstraints"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * A NULL value will be returned if there is no Name Constraints extension.
+ * "plContext" - Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a NameConstraints Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_CertNameConstraints_Create(
+ CERTCertificate *nssCert,
+ PKIX_PL_CertNameConstraints **pNameConstraints,
+ void *plContext)
+{
+ PKIX_PL_CertNameConstraints *nameConstraints = NULL;
+ CERTNameConstraints *nssNameConstraints = NULL;
+ PLArenaPool *arena = NULL;
+ SECStatus status;
+
+ PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_Create");
+ PKIX_NULLCHECK_THREE(nssCert, pNameConstraints, nssCert->arena);
+
+ PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_NewArena).\n");
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling CERT_FindNameConstraintsExten\n");
+ status = CERT_FindNameConstraintsExten
+ (arena, nssCert, &nssNameConstraints);
+
+ if (status != SECSuccess) {
+ PKIX_ERROR(PKIX_DECODINGCERTNAMECONSTRAINTSFAILED);
+ }
+
+ if (nssNameConstraints == NULL) {
+ *pNameConstraints = NULL;
+ if (arena){
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling PORT_FreeArena).\n");
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ goto cleanup;
+ }
+
+ PKIX_CHECK(pkix_pl_CertNameConstraints_Create_Helper
+ (nssNameConstraints, &nameConstraints, plContext),
+ PKIX_CERTNAMECONSTRAINTSCREATEHELPERFAILED);
+
+ nameConstraints->arena = arena;
+
+ *pNameConstraints = nameConstraints;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ if (arena){
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling PORT_FreeArena).\n");
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ }
+
+ PKIX_RETURN(CERTNAMECONSTRAINTS);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertNameConstraints_CreateByMerge
+ *
+ * DESCRIPTION:
+ *
+ * This function allocates and creates a PKIX_PL_NameConstraint object
+ * for merging. It also allocates CERTNameConstraints data space for the
+ * merged NSS NameConstraints data.
+ *
+ * PARAMETERS
+ * "pNameConstraints"
+ * Address where object pointer will be stored and returned.
+ * Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a NameConstraints Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CertNameConstraints_CreateByMerge(
+ PKIX_PL_CertNameConstraints **pNameConstraints,
+ void *plContext)
+{
+ PKIX_PL_CertNameConstraints *nameConstraints = NULL;
+ CERTNameConstraints *nssNameConstraints = NULL;
+ PLArenaPool *arena = NULL;
+
+ PKIX_ENTER(CERTNAMECONSTRAINTS,
+ "pkix_pl_CertNameConstraints_CreateByMerge");
+ PKIX_NULLCHECK_ONE(pNameConstraints);
+
+ PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_NewArena).\n");
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_ArenaZNew).\n");
+ nssNameConstraints = PORT_ArenaZNew(arena, CERTNameConstraints);
+ if (nssNameConstraints == NULL) {
+ PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
+ }
+
+ nssNameConstraints->permited = NULL;
+ nssNameConstraints->excluded = NULL;
+ nssNameConstraints->DERPermited = NULL;
+ nssNameConstraints->DERExcluded = NULL;
+
+ PKIX_CHECK(pkix_pl_CertNameConstraints_Create_Helper
+ (nssNameConstraints, &nameConstraints, plContext),
+ PKIX_CERTNAMECONSTRAINTSCREATEHELPERFAILED);
+
+ nameConstraints->arena = arena;
+
+ *pNameConstraints = nameConstraints;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ if (arena){
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling PORT_FreeArena).\n");
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ }
+
+ PKIX_RETURN(CERTNAMECONSTRAINTS);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertNameConstraints_CopyNssNameConstraints
+ *
+ * DESCRIPTION:
+ *
+ * This function allocates and copies data to a NSS CERTNameConstraints from
+ * the NameConstraints given by "srcNC" and stores the result at "pDestNC". It
+ * copies items on both the permitted and excluded lists, but not the
+ * DERPermited and DERExcluded.
+ *
+ * PARAMETERS
+ * "arena"
+ * Memory pool where object data is allocated from. Must be non-NULL.
+ * "srcNC"
+ * Address of the NameConstraints to copy from. Must be non-NULL.
+ * "pDestNC"
+ * Address where new copied object is stored and returned.
+ * Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a NameConstraints Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_CertNameConstraints_CopyNssNameConstraints(
+ PLArenaPool *arena,
+ CERTNameConstraints *srcNC,
+ CERTNameConstraints **pDestNC,
+ void *plContext)
+{
+ CERTNameConstraints *nssNameConstraints = NULL;
+ CERTNameConstraint *nssNameConstraintHead = NULL;
+ CERTNameConstraint *nssCurrent = NULL;
+ CERTNameConstraint *nssCopyTo = NULL;
+ CERTNameConstraint *nssCopyFrom = NULL;
+
+ PKIX_ENTER(CERTNAMECONSTRAINTS,
+ "pkix_pl_CertNameConstraints_CopyNssNameConstraints");
+ PKIX_NULLCHECK_THREE(arena, srcNC, pDestNC);
+
+ PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_ArenaZNew).\n");
+ nssNameConstraints = PORT_ArenaZNew(arena, CERTNameConstraints);
+ if (nssNameConstraints == NULL) {
+ PKIX_ERROR(PKIX_PORTARENAALLOCFAILED);
+ }
+
+ if (srcNC->permited) {
+
+ nssCopyFrom = srcNC->permited;
+
+ do {
+
+ nssCopyTo = NULL;
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling CERT_CopyNameConstraint).\n");
+ nssCopyTo = CERT_CopyNameConstraint
+ (arena, nssCopyTo, nssCopyFrom);
+ if (nssCopyTo == NULL) {
+ PKIX_ERROR(PKIX_CERTCOPYNAMECONSTRAINTFAILED);
+ }
+ if (nssCurrent == NULL) {
+ nssCurrent = nssNameConstraintHead = nssCopyTo;
+ } else {
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling CERT_AddNameConstraint).\n");
+ nssCurrent = CERT_AddNameConstraint
+ (nssCurrent, nssCopyTo);
+ }
+
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling CERT_GetNextNameConstrain).\n");
+ nssCopyFrom = CERT_GetNextNameConstraint(nssCopyFrom);
+
+ } while (nssCopyFrom != srcNC->permited);
+
+ nssNameConstraints->permited = nssNameConstraintHead;
+ }
+
+ if (srcNC->excluded) {
+
+ nssCurrent = NULL;
+ nssCopyFrom = srcNC->excluded;
+
+ do {
+
+ /*
+ * Cannot use CERT_DupGeneralNameList, which just increments
+ * refcount. We need our own copy since arena is for each
+ * PKIX_PL_NameConstraints. Perhaps contribute this code
+ * as CERT_CopyGeneralNameList (in the future).
+ */
+ nssCopyTo = NULL;
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling CERT_CopyNameConstraint).\n");
+ nssCopyTo = CERT_CopyNameConstraint
+ (arena, nssCopyTo, nssCopyFrom);
+ if (nssCopyTo == NULL) {
+ PKIX_ERROR(PKIX_CERTCOPYNAMECONSTRAINTFAILED);
+ }
+ if (nssCurrent == NULL) {
+ nssCurrent = nssNameConstraintHead = nssCopyTo;
+ } else {
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling CERT_AddNameConstraint).\n");
+ nssCurrent = CERT_AddNameConstraint
+ (nssCurrent, nssCopyTo);
+ }
+
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling CERT_GetNextNameConstrain).\n");
+ nssCopyFrom = CERT_GetNextNameConstraint(nssCopyFrom);
+
+ } while (nssCopyFrom != srcNC->excluded);
+
+ nssNameConstraints->excluded = nssNameConstraintHead;
+ }
+
+ *pDestNC = nssNameConstraints;
+
+cleanup:
+
+ PKIX_RETURN(CERTNAMECONSTRAINTS);
+}
+
+/*
+ * FUNCTION: pkix_pl_CertNameConstraints_Merge
+ *
+ * DESCRIPTION:
+ *
+ * This function merges two NameConstraints pointed to by "firstNC" and
+ * "secondNC" and stores the result in "pMergedNC".
+ *
+ * PARAMETERS
+ * "firstNC"
+ * Address of the first NameConstraints to be merged. Must be non-NULL.
+ * "secondNC"
+ * Address of the second NameConstraints to be merged. Must be non-NULL.
+ * "pMergedNC"
+ * Address where the merge result is stored and returned. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a NameConstraints Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_CertNameConstraints_Merge(
+ PKIX_PL_CertNameConstraints *firstNC,
+ PKIX_PL_CertNameConstraints *secondNC,
+ PKIX_PL_CertNameConstraints **pMergedNC,
+ void *plContext)
+{
+ PKIX_PL_CertNameConstraints *nameConstraints = NULL;
+ CERTNameConstraints **nssNCto = NULL;
+ CERTNameConstraints **nssNCfrom = NULL;
+ CERTNameConstraints *nssNameConstraints = NULL;
+ PKIX_UInt32 numNssItems = 0;
+ PKIX_UInt32 i;
+
+ PKIX_ENTER(CERTNAMECONSTRAINTS, "pkix_pl_CertNameConstraints_Merge");
+ PKIX_NULLCHECK_THREE(firstNC, secondNC, pMergedNC);
+
+ PKIX_CHECK(pkix_pl_CertNameConstraints_CreateByMerge
+ (&nameConstraints, plContext),
+ PKIX_CERTNAMECONSTRAINTSCREATEBYMERGEFAILED);
+
+ /* Merge NSSCertConstraint lists */
+
+ numNssItems = firstNC->numNssNameConstraints +
+ secondNC->numNssNameConstraints;
+
+ /* Free the default space (only one entry) allocated by create */
+ PKIX_CHECK(PKIX_PL_Free
+ (nameConstraints->nssNameConstraintsList, plContext),
+ PKIX_FREEFAILED);
+
+ /* Reallocate the size we need */
+ PKIX_CHECK(PKIX_PL_Malloc
+ (numNssItems * sizeof (CERTNameConstraint *),
+ (void *)&nssNCto,
+ plContext),
+ PKIX_MALLOCFAILED);
+
+ nameConstraints->nssNameConstraintsList = nssNCto;
+
+ nssNCfrom = firstNC->nssNameConstraintsList;
+
+ for (i = 0; i < firstNC->numNssNameConstraints; i++) {
+
+ PKIX_CHECK(pkix_pl_CertNameConstraints_CopyNssNameConstraints
+ (nameConstraints->arena,
+ *nssNCfrom,
+ &nssNameConstraints,
+ plContext),
+ PKIX_CERTNAMECONSTRAINTSCOPYNSSNAMECONSTRAINTSFAILED);
+
+ *nssNCto = nssNameConstraints;
+
+ nssNCto++;
+ nssNCfrom++;
+ }
+
+ nssNCfrom = secondNC->nssNameConstraintsList;
+
+ for (i = 0; i < secondNC->numNssNameConstraints; i++) {
+
+ PKIX_CHECK(pkix_pl_CertNameConstraints_CopyNssNameConstraints
+ (nameConstraints->arena,
+ *nssNCfrom,
+ &nssNameConstraints,
+ plContext),
+ PKIX_CERTNAMECONSTRAINTSCOPYNSSNAMECONSTRAINTSFAILED);
+
+ *nssNCto = nssNameConstraints;
+
+ nssNCto++;
+ nssNCfrom++;
+ }
+
+ nameConstraints->numNssNameConstraints = numNssItems;
+ nameConstraints->permittedList = NULL;
+ nameConstraints->excludedList = NULL;
+
+ *pMergedNC = nameConstraints;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(nameConstraints);
+ }
+
+ PKIX_RETURN(CERTNAMECONSTRAINTS);
+}
+
+/* --Public-NameConstraints-Functions-------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_CertNameConstraints_CheckNamesInNameSpace
+ * (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_CertNameConstraints_CheckNamesInNameSpace(
+ PKIX_List *nameList, /* List of PKIX_PL_GeneralName */
+ PKIX_PL_CertNameConstraints *nameConstraints,
+ PKIX_Boolean *pCheckPass,
+ void *plContext)
+{
+ CERTNameConstraints **nssNameConstraintsList = NULL;
+ CERTNameConstraints *nssNameConstraints = NULL;
+ CERTGeneralName *nssMatchName = NULL;
+ PLArenaPool *arena = NULL;
+ PKIX_PL_GeneralName *name = NULL;
+ PKIX_UInt32 numNameItems = 0;
+ PKIX_UInt32 numNCItems = 0;
+ PKIX_UInt32 i, j;
+ SECStatus status = SECSuccess;
+
+ PKIX_ENTER(CERTNAMECONSTRAINTS,
+ "PKIX_PL_CertNameConstraints_CheckNamesInNameSpace");
+ PKIX_NULLCHECK_TWO(nameConstraints, pCheckPass);
+
+ *pCheckPass = PKIX_TRUE;
+
+ if (nameList != NULL) {
+
+ PKIX_CERTNAMECONSTRAINTS_DEBUG("\t\tCalling PORT_NewArena\n");
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ nssNameConstraintsList =
+ nameConstraints->nssNameConstraintsList;
+ PKIX_NULLCHECK_ONE(nssNameConstraintsList);
+ numNCItems = nameConstraints->numNssNameConstraints;
+
+ PKIX_CHECK(PKIX_List_GetLength
+ (nameList, &numNameItems, plContext),
+ PKIX_LISTGETLENGTHFAILED);
+
+ for (i = 0; i < numNameItems; i++) {
+
+ PKIX_CHECK(PKIX_List_GetItem
+ (nameList,
+ i,
+ (PKIX_PL_Object **) &name,
+ plContext),
+ PKIX_LISTGETITEMFAILED);
+
+ PKIX_CHECK(pkix_pl_GeneralName_GetNssGeneralName
+ (name, &nssMatchName, plContext),
+ PKIX_GENERALNAMEGETNSSGENERALNAMEFAILED);
+
+ PKIX_DECREF(name);
+
+ for (j = 0; j < numNCItems; j++) {
+
+ nssNameConstraints = *(nssNameConstraintsList + j);
+ PKIX_NULLCHECK_ONE(nssNameConstraints);
+
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling CERT_CheckNameSpace\n");
+ status = CERT_CheckNameSpace
+ (arena, nssNameConstraints, nssMatchName);
+ if (status != SECSuccess) {
+ break;
+ }
+
+ }
+
+ if (status != SECSuccess) {
+ break;
+ }
+
+ }
+ }
+
+ if (status == SECFailure) {
+ *pCheckPass = PKIX_FALSE;
+ }
+
+cleanup:
+
+ if (arena){
+ PKIX_CERTNAMECONSTRAINTS_DEBUG
+ ("\t\tCalling PORT_FreeArena).\n");
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+
+ PKIX_RETURN(CERTNAMECONSTRAINTS);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.h
new file mode 100644
index 000000000..2f305ac10
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_nameconstraints.h
@@ -0,0 +1,68 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_nameconstraints.h
+ *
+ * Name Constraints Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_NAMECONSTRAINTS_H
+#define _PKIX_PL_NAMECONSTRAINTS_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_CertNameConstraintsStruct {
+ PLArenaPool *arena;
+ CERTNameConstraints **nssNameConstraintsList;
+ PKIX_UInt32 numNssNameConstraints;
+ PKIX_List *permittedList; /* list of PKIX_PL_GeneralName */
+ PKIX_List *excludedList; /* list of PKIX_PL_GeneralName */
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_CertNameConstraints_RegisterSelf(void *plContext);
+
+PKIX_Error *pkix_pl_CertNameConstraints_Create(
+ CERTCertificate *nssCert,
+ PKIX_PL_CertNameConstraints **pNameConstraints,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_CertNameConstraints_CreateWithNames(
+ PKIX_List *names, /* List of PKIX_PL_GeneralName */
+ PKIX_PL_CertNameConstraints **pNameConstraints,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_CertNameConstraints_CheckNameSpaceNssNames(
+ CERTGeneralName *nssSubjectNames,
+ PKIX_PL_CertNameConstraints *nameConstraints,
+ PKIX_Boolean *pCheckPass,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_CertNameConstraints_CheckNameSpacePkixNames(
+ PKIX_List *nameList,
+ PKIX_PL_CertNameConstraints *nameConstraints,
+ PKIX_Boolean *pCheckPass,
+ void *plContext);
+
+
+PKIX_Error *pkix_pl_CertNameConstraints_Merge(
+ PKIX_PL_CertNameConstraints *firstNC,
+ PKIX_PL_CertNameConstraints *secondNC,
+ PKIX_PL_CertNameConstraints **pMergedNC,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_NAMECONSTRAINTS_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.c
new file mode 100644
index 000000000..679811dec
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.c
@@ -0,0 +1,251 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_ocspcertid.c
+ *
+ * Certificate ID Object for OCSP
+ *
+ */
+
+#include "pkix_pl_ocspcertid.h"
+
+/* --Private-Cert-Functions------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_OcspCertID_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_OcspCertID_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_OcspCertID *certID = NULL;
+
+ PKIX_ENTER(OCSPCERTID, "pkix_pl_OcspCertID_Destroy");
+
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPCERTID_TYPE, plContext),
+ PKIX_OBJECTNOTOCSPCERTID);
+
+ certID = (PKIX_PL_OcspCertID *)object;
+
+ if (certID->certID) {
+ CERT_DestroyOCSPCertID(certID->certID);
+ }
+
+cleanup:
+
+ PKIX_RETURN(OCSPCERTID);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspCertID_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_PUBLICKEY_TYPE and its related functions
+ * with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_OcspCertID_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(OCSPCERTID, "pkix_pl_OcspCertID_RegisterSelf");
+
+ entry.description = "OcspCertID";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_OcspCertID);
+ entry.destructor = pkix_pl_OcspCertID_Destroy;
+ entry.equalsFunction = NULL;
+ entry.hashcodeFunction = NULL;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+ systemClasses[PKIX_OCSPCERTID_TYPE] = entry;
+
+ PKIX_RETURN(OCSPCERTID);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_OcspCertID_Create
+ * DESCRIPTION:
+ *
+ * This function creates an OcspCertID for a given certificate,
+ * to be used with OCSP transactions.
+ *
+ * If a Date is provided in "validity" it may be used in the search for the
+ * issuer of "cert" but has no effect on the request itself.
+ *
+ * PARAMETERS:
+ * "cert"
+ * Address of the Cert for which an OcspCertID is to be created. Must be
+ * non-NULL.
+ * "validity"
+ * Address of the Date for which the Cert's validity is to be determined.
+ * May be NULL.
+ * "object"
+ * Address at which the result is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an OcspCertID Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+PKIX_PL_OcspCertID_Create(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_Date *validity,
+ PKIX_PL_OcspCertID **object,
+ void *plContext)
+{
+ PKIX_PL_OcspCertID *cid = NULL;
+ PRTime time = 0;
+
+ PKIX_ENTER(DATE, "PKIX_PL_OcspCertID_Create");
+ PKIX_NULLCHECK_TWO(cert, object);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_OCSPCERTID_TYPE,
+ sizeof (PKIX_PL_OcspCertID),
+ (PKIX_PL_Object **)&cid,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ if (validity != NULL) {
+ PKIX_CHECK(pkix_pl_Date_GetPRTime(validity, &time, plContext),
+ PKIX_DATEGETPRTIMEFAILED);
+ } else {
+ time = PR_Now();
+ }
+
+ cid->certID = CERT_CreateOCSPCertID(cert->nssCert, time);
+ if (!cid->certID) {
+ PKIX_ERROR(PKIX_COULDNOTCREATEOBJECT);
+ }
+
+ *object = cid;
+ cid = NULL;
+cleanup:
+ PKIX_DECREF(cid);
+ PKIX_RETURN(OCSPCERTID);
+}
+
+/*
+ * FUNCTION: PKIX_PL_OcspCertID_GetFreshCacheStatus
+ * DESCRIPTION:
+ *
+ * This function may return cached OCSP results for the provided
+ * certificate, but only if stored information is still considered to be
+ * fresh.
+ *
+ * PARAMETERS
+ * "cid"
+ * A certificate ID as used by OCSP
+ * "validity"
+ * Optional date parameter to request validity for a specifc time.
+ * "hasFreshStatus"
+ * Output parameter, if the function successed to find fresh cached
+ * information, this will be set to true. Must be non-NULL.
+ * "statusIsGood"
+ * The good/bad result stored in the cache. Must be non-NULL.
+ * "missingResponseError"
+ * If OCSP status is "bad", this variable may indicate the exact
+ * reason why the previous OCSP request had failed.
+ * "plContext"
+ * Platform-specific context pointer.
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an OcspCertID Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+PKIX_PL_OcspCertID_GetFreshCacheStatus(
+ PKIX_PL_OcspCertID *cid,
+ PKIX_PL_Date *validity,
+ PKIX_Boolean *hasFreshStatus,
+ PKIX_Boolean *statusIsGood,
+ SECErrorCodes *missingResponseError,
+ void *plContext)
+{
+ PRTime time = 0;
+ SECStatus rv;
+ SECStatus rvOcsp;
+ OCSPFreshness freshness;
+
+ PKIX_ENTER(DATE, "PKIX_PL_OcspCertID_GetFreshCacheStatus");
+ PKIX_NULLCHECK_THREE(cid, hasFreshStatus, statusIsGood);
+
+ if (validity != NULL) {
+ PKIX_CHECK(pkix_pl_Date_GetPRTime(validity, &time, plContext),
+ PKIX_DATEGETPRTIMEFAILED);
+ } else {
+ time = PR_Now();
+ }
+
+ rv = ocsp_GetCachedOCSPResponseStatus(
+ cid->certID, time, PR_TRUE, /*ignoreGlobalOcspFailureSetting*/
+ &rvOcsp, missingResponseError, &freshness);
+
+ *hasFreshStatus = (rv == SECSuccess && freshness == ocspFresh);
+ if (*hasFreshStatus) {
+ *statusIsGood = (rvOcsp == SECSuccess);
+ }
+cleanup:
+ PKIX_RETURN(OCSPCERTID);
+}
+
+/*
+ * FUNCTION: PKIX_PL_OcspCertID_RememberOCSPProcessingFailure
+ * DESCRIPTION:
+ *
+ * Information about the current failure associated to the given certID
+ * will be remembered in the cache, potentially allowing future calls
+ * to prevent repetitive OCSP requests.
+ * After this function got called, it may no longer be safe to
+ * use the provided cid parameter, because ownership might have been
+ * transfered to the cache. This status will be recorded inside the
+ * cid object.
+ *
+ * PARAMETERS
+ * "cid"
+ * The certificate ID associated to a failed OCSP processing.
+ * "plContext"
+ * Platform-specific context pointer.
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an OcspCertID Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+PKIX_PL_OcspCertID_RememberOCSPProcessingFailure(
+ PKIX_PL_OcspCertID *cid,
+ void *plContext)
+{
+ PRBool certIDWasConsumed = PR_FALSE;
+
+ PKIX_ENTER(DATE, "PKIX_PL_OcspCertID_RememberOCSPProcessingFailure");
+ PKIX_NULLCHECK_TWO(cid, cid->certID);
+
+ cert_RememberOCSPProcessingFailure(cid->certID, &certIDWasConsumed);
+
+ if (certIDWasConsumed) {
+ cid->certID = NULL;
+ }
+
+ PKIX_RETURN(OCSPCERTID);
+}
+
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.h
new file mode 100644
index 000000000..772a12b25
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspcertid.h
@@ -0,0 +1,53 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_ocspcertid.h
+ *
+ * Public Key Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_OCSPCERTID_H
+#define _PKIX_PL_OCSPCERTID_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_OcspCertIDStruct {
+ CERTOCSPCertID *certID;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_OcspCertID_RegisterSelf(void *plContext);
+
+PKIX_Error *
+PKIX_PL_OcspCertID_Create(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_Date *validity,
+ PKIX_PL_OcspCertID **object,
+ void *plContext);
+
+PKIX_Error *
+PKIX_PL_OcspCertID_GetFreshCacheStatus(
+ PKIX_PL_OcspCertID *cid,
+ PKIX_PL_Date *validity,
+ PKIX_Boolean *hasFreshStatus,
+ PKIX_Boolean *statusIsGood,
+ SECErrorCodes *missingResponseError,
+ void *plContext);
+
+PKIX_Error *
+PKIX_PL_OcspCertID_RememberOCSPProcessingFailure(
+ PKIX_PL_OcspCertID *cid,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_OCSPCERTID_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.c
new file mode 100644
index 000000000..171a3d2d9
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.c
@@ -0,0 +1,441 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_ocsprequest.c
+ *
+ */
+
+#include "pkix_pl_ocsprequest.h"
+
+/* --Private-OcspRequest-Functions------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_OcspRequest_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_OcspRequest_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_OcspRequest *ocspReq = NULL;
+
+ PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPREQUEST_TYPE, plContext),
+ PKIX_OBJECTNOTOCSPREQUEST);
+
+ ocspReq = (PKIX_PL_OcspRequest *)object;
+
+ if (ocspReq->decoded != NULL) {
+ CERT_DestroyOCSPRequest(ocspReq->decoded);
+ }
+
+ if (ocspReq->encoded != NULL) {
+ SECITEM_FreeItem(ocspReq->encoded, PR_TRUE);
+ }
+
+ if (ocspReq->location != NULL) {
+ PORT_Free(ocspReq->location);
+ }
+
+ PKIX_DECREF(ocspReq->cert);
+ PKIX_DECREF(ocspReq->validity);
+ PKIX_DECREF(ocspReq->signerCert);
+
+cleanup:
+
+ PKIX_RETURN(OCSPREQUEST);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspRequest_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_OcspRequest_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_UInt32 certHash = 0;
+ PKIX_UInt32 dateHash = 0;
+ PKIX_UInt32 extensionHash = 0;
+ PKIX_UInt32 signerHash = 0;
+ PKIX_PL_OcspRequest *ocspRq = NULL;
+
+ PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPREQUEST_TYPE, plContext),
+ PKIX_OBJECTNOTOCSPREQUEST);
+
+ ocspRq = (PKIX_PL_OcspRequest *)object;
+
+ *pHashcode = 0;
+
+ PKIX_HASHCODE(ocspRq->cert, &certHash, plContext,
+ PKIX_CERTHASHCODEFAILED);
+
+ PKIX_HASHCODE(ocspRq->validity, &dateHash, plContext,
+ PKIX_DATEHASHCODEFAILED);
+
+ if (ocspRq->addServiceLocator == PKIX_TRUE) {
+ extensionHash = 0xff;
+ }
+
+ PKIX_HASHCODE(ocspRq->signerCert, &signerHash, plContext,
+ PKIX_CERTHASHCODEFAILED);
+
+ *pHashcode = (((((extensionHash << 8) || certHash) << 8) ||
+ dateHash) << 8) || signerHash;
+
+cleanup:
+
+ PKIX_RETURN(OCSPREQUEST);
+
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspRequest_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_OcspRequest_Equals(
+ PKIX_PL_Object *firstObj,
+ PKIX_PL_Object *secondObj,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_Boolean match = PKIX_FALSE;
+ PKIX_UInt32 secondType = 0;
+ PKIX_PL_OcspRequest *firstReq = NULL;
+ PKIX_PL_OcspRequest *secondReq = NULL;
+
+ PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Equals");
+ PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult);
+
+ /* test that firstObj is a OcspRequest */
+ PKIX_CHECK(pkix_CheckType(firstObj, PKIX_OCSPREQUEST_TYPE, plContext),
+ PKIX_FIRSTOBJARGUMENTNOTOCSPREQUEST);
+
+ /*
+ * Since we know firstObj is a OcspRequest, if both references are
+ * identical, they must be equal
+ */
+ if (firstObj == secondObj){
+ match = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondObj isn't a OcspRequest, we don't throw an error.
+ * We simply return a Boolean result of FALSE
+ */
+ PKIX_CHECK(PKIX_PL_Object_GetType
+ (secondObj, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+ if (secondType != PKIX_OCSPREQUEST_TYPE) {
+ goto cleanup;
+ }
+
+ firstReq = (PKIX_PL_OcspRequest *)firstObj;
+ secondReq = (PKIX_PL_OcspRequest *)secondObj;
+
+ if (firstReq->addServiceLocator != secondReq->addServiceLocator) {
+ goto cleanup;
+ }
+
+ PKIX_EQUALS(firstReq->cert, secondReq->cert, &match, plContext,
+ PKIX_CERTEQUALSFAILED);
+
+ if (match == PKIX_FALSE) {
+ goto cleanup;
+ }
+
+ PKIX_EQUALS(firstReq->validity, secondReq->validity, &match, plContext,
+ PKIX_DATEEQUALSFAILED);
+
+ if (match == PKIX_FALSE) {
+ goto cleanup;
+ }
+
+ PKIX_EQUALS
+ (firstReq->signerCert, secondReq->signerCert, &match, plContext,
+ PKIX_CERTEQUALSFAILED);
+
+cleanup:
+
+ *pResult = match;
+
+ PKIX_RETURN(OCSPREQUEST);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspRequest_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_OCSPREQUEST_TYPE and its related functions with
+ * systemClasses[]
+ * PARAMETERS:
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_OcspRequest_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_RegisterSelf");
+
+ entry.description = "OcspRequest";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_OcspRequest);
+ entry.destructor = pkix_pl_OcspRequest_Destroy;
+ entry.equalsFunction = pkix_pl_OcspRequest_Equals;
+ entry.hashcodeFunction = pkix_pl_OcspRequest_Hashcode;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_OCSPREQUEST_TYPE] = entry;
+
+ PKIX_RETURN(OCSPREQUEST);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_OcspRequest_Create
+ * DESCRIPTION:
+ *
+ * This function creates an OcspRequest to be used in validating the Cert
+ * pointed to by "cert" and storing the result at "pRequest". If a URI
+ * is found for an OCSP responder, PKIX_TRUE is stored at "pURIFound". If no
+ * URI is found, PKIX_FALSE is stored.
+ *
+ * If a Date is provided in "validity" it may be used in the search for the
+ * issuer of "cert" but has no effect on the request itself. If
+ * "addServiceLocator" is TRUE, the AddServiceLocator extension will be
+ * included in the Request. If "signerCert" is provided it will be used to sign
+ * the Request. (Note: this signed request feature is not currently supported.)
+ *
+ * PARAMETERS:
+ * "cert"
+ * Address of the Cert for which an OcspRequest is to be created. Must be
+ * non-NULL.
+ * "validity"
+ * Address of the Date for which the Cert's validity is to be determined.
+ * May be NULL.
+ * "signerCert"
+ * Address of the Cert to be used, if present, in signing the request.
+ * May be NULL.
+ * "pRequest"
+ * Address at which the result is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an OcspRequest Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_OcspRequest_Create(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_OcspCertID *cid,
+ PKIX_PL_Date *validity,
+ PKIX_PL_Cert *signerCert,
+ PKIX_UInt32 methodFlags,
+ PKIX_Boolean *pURIFound,
+ PKIX_PL_OcspRequest **pRequest,
+ void *plContext)
+{
+ PKIX_PL_OcspRequest *ocspRequest = NULL;
+
+ CERTCertDBHandle *handle = NULL;
+ SECStatus rv = SECFailure;
+ SECItem *encoding = NULL;
+ CERTOCSPRequest *certRequest = NULL;
+ PRTime time = 0;
+ PRBool addServiceLocatorExtension = PR_FALSE;
+ CERTCertificate *nssCert = NULL;
+ CERTCertificate *nssSignerCert = NULL;
+ char *location = NULL;
+ PRErrorCode locError = 0;
+ PKIX_Boolean canUseDefaultSource = PKIX_FALSE;
+
+ PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_Create");
+ PKIX_NULLCHECK_TWO(cert, pRequest);
+
+ /* create a PKIX_PL_OcspRequest object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_OCSPREQUEST_TYPE,
+ sizeof (PKIX_PL_OcspRequest),
+ (PKIX_PL_Object **)&ocspRequest,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ PKIX_INCREF(cert);
+ ocspRequest->cert = cert;
+
+ PKIX_INCREF(validity);
+ ocspRequest->validity = validity;
+
+ PKIX_INCREF(signerCert);
+ ocspRequest->signerCert = signerCert;
+
+ ocspRequest->decoded = NULL;
+ ocspRequest->encoded = NULL;
+
+ ocspRequest->location = NULL;
+
+ nssCert = cert->nssCert;
+
+ /*
+ * Does this Cert have an Authority Information Access extension with
+ * the URI of an OCSP responder?
+ */
+ handle = CERT_GetDefaultCertDB();
+
+ if (!(methodFlags & PKIX_REV_M_IGNORE_IMPLICIT_DEFAULT_SOURCE)) {
+ canUseDefaultSource = PKIX_TRUE;
+ }
+ location = ocsp_GetResponderLocation(handle, nssCert,
+ canUseDefaultSource,
+ &addServiceLocatorExtension);
+ if (location == NULL) {
+ locError = PORT_GetError();
+ if (locError == SEC_ERROR_EXTENSION_NOT_FOUND ||
+ locError == SEC_ERROR_CERT_BAD_ACCESS_LOCATION) {
+ PORT_SetError(0);
+ *pURIFound = PKIX_FALSE;
+ goto cleanup;
+ }
+ PKIX_ERROR(PKIX_ERRORFINDINGORPROCESSINGURI);
+ }
+
+ ocspRequest->location = location;
+ *pURIFound = PKIX_TRUE;
+
+ if (signerCert != NULL) {
+ nssSignerCert = signerCert->nssCert;
+ }
+
+ if (validity != NULL) {
+ PKIX_CHECK(pkix_pl_Date_GetPRTime(validity, &time, plContext),
+ PKIX_DATEGETPRTIMEFAILED);
+ } else {
+ time = PR_Now();
+ }
+
+ certRequest = cert_CreateSingleCertOCSPRequest(
+ cid->certID, cert->nssCert, time,
+ addServiceLocatorExtension, nssSignerCert);
+
+ ocspRequest->decoded = certRequest;
+
+ if (certRequest == NULL) {
+ PKIX_ERROR(PKIX_UNABLETOCREATECERTOCSPREQUEST);
+ }
+
+ rv = CERT_AddOCSPAcceptableResponses(
+ certRequest, SEC_OID_PKIX_OCSP_BASIC_RESPONSE);
+
+ if (rv == SECFailure) {
+ PKIX_ERROR(PKIX_UNABLETOADDACCEPTABLERESPONSESTOREQUEST);
+ }
+
+ encoding = CERT_EncodeOCSPRequest(NULL, certRequest, NULL);
+
+ ocspRequest->encoded = encoding;
+
+ *pRequest = ocspRequest;
+ ocspRequest = NULL;
+
+cleanup:
+ PKIX_DECREF(ocspRequest);
+
+ PKIX_RETURN(OCSPREQUEST);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspRequest_GetEncoded
+ * DESCRIPTION:
+ *
+ * This function obtains the encoded message from the OcspRequest pointed to
+ * by "request", storing the result at "pRequest".
+ *
+ * PARAMETERS
+ * "request"
+ * The address of the OcspRequest whose encoded message is to be
+ * retrieved. Must be non-NULL.
+ * "pRequest"
+ * The address at which is stored the address of the encoded message. Must
+ * be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_OcspRequest_GetEncoded(
+ PKIX_PL_OcspRequest *request,
+ SECItem **pRequest,
+ void *plContext)
+{
+ PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_GetEncoded");
+ PKIX_NULLCHECK_TWO(request, pRequest);
+
+ *pRequest = request->encoded;
+
+ PKIX_RETURN(OCSPREQUEST);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspRequest_GetLocation
+ * DESCRIPTION:
+ *
+ * This function obtains the location from the OcspRequest pointed to
+ * by "request", storing the result at "pLocation".
+ *
+ * PARAMETERS
+ * "request"
+ * The address of the OcspRequest whose encoded message is to be
+ * retrieved. Must be non-NULL.
+ * "pLocation"
+ * The address at which is stored the address of the location. Must
+ * be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_OcspRequest_GetLocation(
+ PKIX_PL_OcspRequest *request,
+ char **pLocation,
+ void *plContext)
+{
+ PKIX_ENTER(OCSPREQUEST, "pkix_pl_OcspRequest_GetLocation");
+ PKIX_NULLCHECK_TWO(request, pLocation);
+
+ *pLocation = request->location;
+
+ PKIX_RETURN(OCSPREQUEST);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.h
new file mode 100644
index 000000000..fa79266ee
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocsprequest.h
@@ -0,0 +1,61 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_ocsprequest.h
+ *
+ * OcspRequest Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_OCSPREQUEST_H
+#define _PKIX_PL_OCSPREQUEST_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_OcspRequestStruct{
+ PKIX_PL_Cert *cert;
+ PKIX_PL_Date *validity;
+ PKIX_Boolean addServiceLocator;
+ PKIX_PL_Cert *signerCert;
+ CERTOCSPRequest *decoded;
+ SECItem *encoded;
+ char *location;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_pl_OcspRequest_Create(
+ PKIX_PL_Cert *cert,
+ PKIX_PL_OcspCertID *cid,
+ PKIX_PL_Date *validity,
+ PKIX_PL_Cert *signerCert,
+ PKIX_UInt32 methodFlags,
+ PKIX_Boolean *pURIFound,
+ PKIX_PL_OcspRequest **pRequest,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_OcspRequest_GetEncoded(
+ PKIX_PL_OcspRequest *request,
+ SECItem **pRequest,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_OcspRequest_GetLocation(
+ PKIX_PL_OcspRequest *request,
+ char **pLocation,
+ void *plContext);
+
+PKIX_Error *pkix_pl_OcspRequest_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_OCSPREQUEST_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.c
new file mode 100644
index 000000000..fa5d6e9d5
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.c
@@ -0,0 +1,1067 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_ocspresponse.c
+ *
+ */
+
+#include "pkix_pl_ocspresponse.h"
+
+/* ----Public functions------------------------------------- */
+/*
+ * This is the libpkix replacement for CERT_VerifyOCSPResponseSignature.
+ * It is used if it has been set as the verifyFcn member of ocspChecker.
+ */
+PKIX_Error *
+PKIX_PL_OcspResponse_UseBuildChain(
+ PKIX_PL_Cert *signerCert,
+ PKIX_PL_Date *producedAt,
+ PKIX_ProcessingParams *procParams,
+ void **pNBIOContext,
+ void **pState,
+ PKIX_BuildResult **pBuildResult,
+ PKIX_VerifyNode **pVerifyTree,
+ void *plContext)
+{
+ PKIX_ProcessingParams *caProcParams = NULL;
+ PKIX_PL_Date *date = NULL;
+ PKIX_ComCertSelParams *certSelParams = NULL;
+ PKIX_CertSelector *certSelector = NULL;
+ void *nbioContext = NULL;
+ PKIX_Error *buildError = NULL;
+
+ PKIX_ENTER(OCSPRESPONSE, "pkix_OcspResponse_UseBuildChain");
+ PKIX_NULLCHECK_THREE(signerCert, producedAt, procParams);
+ PKIX_NULLCHECK_THREE(pNBIOContext, pState, pBuildResult);
+
+ nbioContext = *pNBIOContext;
+ *pNBIOContext = NULL;
+
+ /* Are we resuming after a WOULDBLOCK return, or starting anew ? */
+ if (nbioContext == NULL) {
+ /* Starting anew */
+ PKIX_CHECK(PKIX_PL_Object_Duplicate
+ ((PKIX_PL_Object *)procParams,
+ (PKIX_PL_Object **)&caProcParams,
+ plContext),
+ PKIX_OBJECTDUPLICATEFAILED);
+
+ PKIX_CHECK(PKIX_ProcessingParams_SetDate(procParams, date, plContext),
+ PKIX_PROCESSINGPARAMSSETDATEFAILED);
+
+ /* create CertSelector with target certificate in params */
+
+ PKIX_CHECK(PKIX_CertSelector_Create
+ (NULL, NULL, &certSelector, plContext),
+ PKIX_CERTSELECTORCREATEFAILED);
+
+ PKIX_CHECK(PKIX_ComCertSelParams_Create
+ (&certSelParams, plContext),
+ PKIX_COMCERTSELPARAMSCREATEFAILED);
+
+ PKIX_CHECK(PKIX_ComCertSelParams_SetCertificate
+ (certSelParams, signerCert, plContext),
+ PKIX_COMCERTSELPARAMSSETCERTIFICATEFAILED);
+
+ PKIX_CHECK(PKIX_CertSelector_SetCommonCertSelectorParams
+ (certSelector, certSelParams, plContext),
+ PKIX_CERTSELECTORSETCOMMONCERTSELECTORPARAMSFAILED);
+
+ PKIX_CHECK(PKIX_ProcessingParams_SetTargetCertConstraints
+ (caProcParams, certSelector, plContext),
+ PKIX_PROCESSINGPARAMSSETTARGETCERTCONSTRAINTSFAILED);
+ }
+
+ buildError = PKIX_BuildChain
+ (caProcParams,
+ &nbioContext,
+ pState,
+ pBuildResult,
+ pVerifyTree,
+ plContext);
+
+ /* non-null nbioContext means the build would block */
+ if (nbioContext != NULL) {
+
+ *pNBIOContext = nbioContext;
+
+ /* no buildResult means the build has failed */
+ } else if (buildError) {
+ pkixErrorResult = buildError;
+ buildError = NULL;
+ } else {
+ PKIX_DECREF(*pState);
+ }
+
+cleanup:
+
+ PKIX_DECREF(caProcParams);
+ PKIX_DECREF(date);
+ PKIX_DECREF(certSelParams);
+ PKIX_DECREF(certSelector);
+
+ PKIX_RETURN(OCSPRESPONSE);
+}
+
+/* --Private-OcspResponse-Functions------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_OcspResponse_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_OcspResponse *ocspRsp = NULL;
+ const SEC_HttpClientFcn *httpClient = NULL;
+ const SEC_HttpClientFcnV1 *hcv1 = NULL;
+
+ PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPRESPONSE_TYPE, plContext),
+ PKIX_OBJECTNOTANOCSPRESPONSE);
+
+ ocspRsp = (PKIX_PL_OcspResponse *)object;
+
+ if (ocspRsp->nssOCSPResponse != NULL) {
+ CERT_DestroyOCSPResponse(ocspRsp->nssOCSPResponse);
+ ocspRsp->nssOCSPResponse = NULL;
+ }
+
+ if (ocspRsp->signerCert != NULL) {
+ CERT_DestroyCertificate(ocspRsp->signerCert);
+ ocspRsp->signerCert = NULL;
+ }
+
+ httpClient = (const SEC_HttpClientFcn *)(ocspRsp->httpClient);
+
+ if (httpClient && (httpClient->version == 1)) {
+
+ hcv1 = &(httpClient->fcnTable.ftable1);
+
+ if (ocspRsp->sessionRequest != NULL) {
+ (*hcv1->freeFcn)(ocspRsp->sessionRequest);
+ ocspRsp->sessionRequest = NULL;
+ }
+
+ if (ocspRsp->serverSession != NULL) {
+ (*hcv1->freeSessionFcn)(ocspRsp->serverSession);
+ ocspRsp->serverSession = NULL;
+ }
+ }
+
+ if (ocspRsp->arena != NULL) {
+ PORT_FreeArena(ocspRsp->arena, PR_FALSE);
+ ocspRsp->arena = NULL;
+ }
+
+ PKIX_DECREF(ocspRsp->producedAtDate);
+ PKIX_DECREF(ocspRsp->pkixSignerCert);
+ PKIX_DECREF(ocspRsp->request);
+
+cleanup:
+
+ PKIX_RETURN(OCSPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_OcspResponse_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_OcspResponse *ocspRsp = NULL;
+
+ PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_OCSPRESPONSE_TYPE, plContext),
+ PKIX_OBJECTNOTANOCSPRESPONSE);
+
+ ocspRsp = (PKIX_PL_OcspResponse *)object;
+
+ if (ocspRsp->encodedResponse->data == NULL) {
+ *pHashcode = 0;
+ } else {
+ PKIX_CHECK(pkix_hash
+ (ocspRsp->encodedResponse->data,
+ ocspRsp->encodedResponse->len,
+ pHashcode,
+ plContext),
+ PKIX_HASHFAILED);
+ }
+
+cleanup:
+
+ PKIX_RETURN(OCSPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_OcspResponse_Equals(
+ PKIX_PL_Object *firstObj,
+ PKIX_PL_Object *secondObj,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_UInt32 secondType = 0;
+ PKIX_UInt32 firstLen = 0;
+ PKIX_UInt32 i = 0;
+ PKIX_PL_OcspResponse *rsp1 = NULL;
+ PKIX_PL_OcspResponse *rsp2 = NULL;
+ const unsigned char *firstData = NULL;
+ const unsigned char *secondData = NULL;
+
+ PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Equals");
+ PKIX_NULLCHECK_THREE(firstObj, secondObj, pResult);
+
+ /* test that firstObj is a OcspResponse */
+ PKIX_CHECK(pkix_CheckType(firstObj, PKIX_OCSPRESPONSE_TYPE, plContext),
+ PKIX_FIRSTOBJARGUMENTNOTANOCSPRESPONSE);
+
+ /*
+ * Since we know firstObj is a OcspResponse, if both references are
+ * identical, they must be equal
+ */
+ if (firstObj == secondObj){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondObj isn't a OcspResponse, we don't throw an error.
+ * We simply return a Boolean result of FALSE
+ */
+ *pResult = PKIX_FALSE;
+ PKIX_CHECK(PKIX_PL_Object_GetType(secondObj, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+ if (secondType != PKIX_OCSPRESPONSE_TYPE) {
+ goto cleanup;
+ }
+
+ rsp1 = (PKIX_PL_OcspResponse *)firstObj;
+ rsp2 = (PKIX_PL_OcspResponse *)secondObj;
+
+ /* If either lacks an encoded string, they cannot be compared */
+ firstData = (const unsigned char *)rsp1->encodedResponse->data;
+ secondData = (const unsigned char *)rsp2->encodedResponse->data;
+ if ((firstData == NULL) || (secondData == NULL)) {
+ goto cleanup;
+ }
+
+ firstLen = rsp1->encodedResponse->len;
+
+ if (firstLen != rsp2->encodedResponse->len) {
+ goto cleanup;
+ }
+
+ for (i = 0; i < firstLen; i++) {
+ if (*firstData++ != *secondData++) {
+ goto cleanup;
+ }
+ }
+
+ *pResult = PKIX_TRUE;
+
+cleanup:
+
+ PKIX_RETURN(OCSPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_OCSPRESPONSE_TYPE and its related functions with
+ * systemClasses[]
+ * PARAMETERS:
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_OcspResponse_RegisterSelf(void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry *entry = &systemClasses[PKIX_OCSPRESPONSE_TYPE];
+
+ PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_RegisterSelf");
+
+ entry->description = "OcspResponse";
+ entry->typeObjectSize = sizeof(PKIX_PL_OcspResponse);
+ entry->destructor = pkix_pl_OcspResponse_Destroy;
+ entry->equalsFunction = pkix_pl_OcspResponse_Equals;
+ entry->hashcodeFunction = pkix_pl_OcspResponse_Hashcode;
+ entry->duplicateFunction = pkix_duplicateImmutable;
+
+ PKIX_RETURN(OCSPRESPONSE);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_Create
+ * DESCRIPTION:
+ *
+ * This function transmits the OcspRequest pointed to by "request" and obtains
+ * an OcspResponse, which it stores at "pOcspResponse". If the HTTPClient
+ * supports non-blocking I/O this function may store a non-NULL value at
+ * "pNBIOContext" (the WOULDBLOCK condition). In that case the caller should
+ * make a subsequent call with the same value in "pNBIOContext" and
+ * "pOcspResponse" to resume the operation. Additional WOULDBLOCK returns may
+ * occur; the caller should persist until a return occurs with NULL stored at
+ * "pNBIOContext".
+ *
+ * If a SEC_HttpClientFcn "responder" is supplied, it is used as the client
+ * to which the OCSP query is sent. If none is supplied, the default responder
+ * is used.
+ *
+ * If an OcspResponse_VerifyCallback "verifyFcn" is supplied, it is used to
+ * verify the Cert received from the responder as the signer. If none is
+ * supplied, the default verification function is used.
+ *
+ * The contents of "request" are ignored on calls subsequent to a WOULDBLOCK
+ * return, and the caller is permitted to supply NULL.
+ *
+ * PARAMETERS
+ * "request"
+ * Address of the OcspRequest for which a response is desired.
+ * "httpMethod"
+ * GET or POST
+ * "responder"
+ * Address, if non-NULL, of the SEC_HttpClientFcn to be sent the OCSP
+ * query.
+ * "verifyFcn"
+ * Address, if non-NULL, of the OcspResponse_VerifyCallback function to be
+ * used to verify the Cert of the OCSP responder.
+ * "pNBIOContext"
+ * Address at which platform-dependent information is stored for handling
+ * of non-blocking I/O. Must be non-NULL.
+ * "pOcspResponse"
+ * The address where the created OcspResponse is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an OcspResponse Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_OcspResponse_Create(
+ PKIX_PL_OcspRequest *request,
+ const char *httpMethod,
+ void *responder,
+ PKIX_PL_VerifyCallback verifyFcn,
+ void **pNBIOContext,
+ PKIX_PL_OcspResponse **pResponse,
+ void *plContext)
+{
+ void *nbioContext = NULL;
+ PKIX_PL_OcspResponse *ocspResponse = NULL;
+ const SEC_HttpClientFcn *httpClient = NULL;
+ const SEC_HttpClientFcnV1 *hcv1 = NULL;
+ SECStatus rv = SECFailure;
+ char *location = NULL;
+ char *hostname = NULL;
+ char *path = NULL;
+ char *responseContentType = NULL;
+ PRUint16 port = 0;
+ SEC_HTTP_SERVER_SESSION serverSession = NULL;
+ SEC_HTTP_REQUEST_SESSION sessionRequest = NULL;
+ SECItem *encodedRequest = NULL;
+ PRUint16 responseCode = 0;
+ char *responseData = NULL;
+
+ PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_Create");
+ PKIX_NULLCHECK_TWO(pNBIOContext, pResponse);
+
+ if (!strcmp(httpMethod, "GET") && !strcmp(httpMethod, "POST")) {
+ PKIX_ERROR(PKIX_INVALIDOCSPHTTPMETHOD);
+ }
+
+ nbioContext = *pNBIOContext;
+ *pNBIOContext = NULL;
+
+ if (nbioContext != NULL) {
+
+ ocspResponse = *pResponse;
+ PKIX_NULLCHECK_ONE(ocspResponse);
+
+ httpClient = ocspResponse->httpClient;
+ serverSession = ocspResponse->serverSession;
+ sessionRequest = ocspResponse->sessionRequest;
+ PKIX_NULLCHECK_THREE(httpClient, serverSession, sessionRequest);
+
+ } else {
+ PKIX_UInt32 timeout =
+ ((PKIX_PL_NssContext*)plContext)->timeoutSeconds;
+
+ PKIX_NULLCHECK_ONE(request);
+
+ PKIX_CHECK(pkix_pl_OcspRequest_GetEncoded
+ (request, &encodedRequest, plContext),
+ PKIX_OCSPREQUESTGETENCODEDFAILED);
+
+ /* prepare initial message to HTTPClient */
+
+ /* Is there a default responder and is it enabled? */
+ if (responder) {
+ httpClient = (const SEC_HttpClientFcn *)responder;
+ } else {
+ httpClient = SEC_GetRegisteredHttpClient();
+ }
+
+ if (httpClient && (httpClient->version == 1)) {
+ char *fullGetPath = NULL;
+ const char *sessionPath = NULL;
+ PRBool usePOST = !strcmp(httpMethod, "POST");
+
+ hcv1 = &(httpClient->fcnTable.ftable1);
+
+ PKIX_CHECK(pkix_pl_OcspRequest_GetLocation
+ (request, &location, plContext),
+ PKIX_OCSPREQUESTGETLOCATIONFAILED);
+
+ /* parse location -> hostname, port, path */
+ rv = CERT_ParseURL(location, &hostname, &port, &path);
+ if (rv == SECFailure || hostname == NULL || path == NULL) {
+ PKIX_ERROR(PKIX_URLPARSINGFAILED);
+ }
+
+ rv = (*hcv1->createSessionFcn)(hostname, port,
+ &serverSession);
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_OCSPSERVERERROR);
+ }
+
+ if (usePOST) {
+ sessionPath = path;
+ } else {
+ /* calculate, are we allowed to use GET? */
+ enum { max_get_request_size = 255 }; /* defined by RFC2560 */
+ char b64ReqBuf[max_get_request_size+1];
+ size_t base64size;
+ size_t slashLengthIfNeeded = 0;
+ size_t pathLength;
+ PRInt32 urlEncodedBufLength;
+ size_t getURLLength;
+ char *walkOutput = NULL;
+
+ pathLength = strlen(path);
+ if (path[pathLength-1] != '/') {
+ slashLengthIfNeeded = 1;
+ }
+ base64size = (((encodedRequest->len +2)/3) * 4);
+ if (base64size > max_get_request_size) {
+ PKIX_ERROR(PKIX_OCSPGETREQUESTTOOBIG);
+ }
+ memset(b64ReqBuf, 0, sizeof(b64ReqBuf));
+ PL_Base64Encode((const char *)encodedRequest->data, encodedRequest->len, b64ReqBuf);
+ urlEncodedBufLength = ocsp_UrlEncodeBase64Buf(b64ReqBuf, NULL);
+ getURLLength = pathLength + urlEncodedBufLength + slashLengthIfNeeded;
+ fullGetPath = (char*)PORT_Alloc(getURLLength);
+ if (!fullGetPath) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+ strcpy(fullGetPath, path);
+ walkOutput = fullGetPath + pathLength;
+ if (walkOutput > fullGetPath && slashLengthIfNeeded) {
+ strcpy(walkOutput, "/");
+ ++walkOutput;
+ }
+ ocsp_UrlEncodeBase64Buf(b64ReqBuf, walkOutput);
+ sessionPath = fullGetPath;
+ }
+
+ rv = (*hcv1->createFcn)(serverSession, "http",
+ sessionPath, httpMethod,
+ PR_SecondsToInterval(timeout),
+ &sessionRequest);
+ sessionPath = NULL;
+ if (fullGetPath) {
+ PORT_Free(fullGetPath);
+ fullGetPath = NULL;
+ }
+
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_OCSPSERVERERROR);
+ }
+
+ if (usePOST) {
+ rv = (*hcv1->setPostDataFcn)(sessionRequest,
+ (char *)encodedRequest->data,
+ encodedRequest->len,
+ "application/ocsp-request");
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_OCSPSERVERERROR);
+ }
+ }
+
+ /* create a PKIX_PL_OcspResponse object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_OCSPRESPONSE_TYPE,
+ sizeof (PKIX_PL_OcspResponse),
+ (PKIX_PL_Object **)&ocspResponse,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ PKIX_INCREF(request);
+ ocspResponse->request = request;
+ ocspResponse->httpClient = httpClient;
+ ocspResponse->serverSession = serverSession;
+ serverSession = NULL;
+ ocspResponse->sessionRequest = sessionRequest;
+ sessionRequest = NULL;
+ ocspResponse->verifyFcn = verifyFcn;
+ ocspResponse->handle = CERT_GetDefaultCertDB();
+ ocspResponse->encodedResponse = NULL;
+ ocspResponse->arena = NULL;
+ ocspResponse->producedAt = 0;
+ ocspResponse->producedAtDate = NULL;
+ ocspResponse->pkixSignerCert = NULL;
+ ocspResponse->nssOCSPResponse = NULL;
+ ocspResponse->signerCert = NULL;
+ }
+ }
+
+ /* begin or resume IO to HTTPClient */
+ if (httpClient && (httpClient->version == 1)) {
+ PRUint32 responseDataLen =
+ ((PKIX_PL_NssContext*)plContext)->maxResponseLength;
+
+ hcv1 = &(httpClient->fcnTable.ftable1);
+
+ rv = (*hcv1->trySendAndReceiveFcn)(ocspResponse->sessionRequest,
+ (PRPollDesc **)&nbioContext,
+ &responseCode,
+ (const char **)&responseContentType,
+ NULL, /* responseHeaders */
+ (const char **)&responseData,
+ &responseDataLen);
+
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_OCSPSERVERERROR);
+ }
+ /* responseContentType is a pointer to the null-terminated
+ * string returned by httpclient. Memory allocated for context
+ * type will be freed with freeing of the HttpClient struct. */
+ if (PORT_Strcasecmp(responseContentType,
+ "application/ocsp-response")) {
+ PKIX_ERROR(PKIX_OCSPSERVERERROR);
+ }
+ if (nbioContext != NULL) {
+ *pNBIOContext = nbioContext;
+ goto cleanup;
+ }
+ if (responseCode != 200) {
+ PKIX_ERROR(PKIX_OCSPBADHTTPRESPONSE);
+ }
+ ocspResponse->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (ocspResponse->arena == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+ ocspResponse->encodedResponse = SECITEM_AllocItem
+ (ocspResponse->arena, NULL, responseDataLen);
+ if (ocspResponse->encodedResponse == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+ PORT_Memcpy(ocspResponse->encodedResponse->data,
+ responseData, responseDataLen);
+ }
+ *pResponse = ocspResponse;
+ ocspResponse = NULL;
+
+cleanup:
+
+ if (path != NULL) {
+ PORT_Free(path);
+ }
+ if (hostname != NULL) {
+ PORT_Free(hostname);
+ }
+ if (ocspResponse) {
+ PKIX_DECREF(ocspResponse);
+ }
+ if (serverSession) {
+ hcv1->freeSessionFcn(serverSession);
+ }
+ if (sessionRequest) {
+ hcv1->freeFcn(sessionRequest);
+ }
+
+ PKIX_RETURN(OCSPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_Decode
+ * DESCRIPTION:
+ *
+ * This function decodes the DER data contained in the OcspResponse pointed to
+ * by "response", storing PKIX_TRUE at "pPassed" if the decoding was
+ * successful, and PKIX_FALSE otherwise.
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the OcspResponse whose DER data is to be decoded. Must
+ * be non-NULL.
+ * "pPassed"
+ * Address at which the Boolean result is stored. Must be non-NULL.
+ * "pReturnCode"
+ * Address at which the SECErrorCodes result is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an OcspResponse Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+
+PKIX_Error *
+pkix_pl_OcspResponse_Decode(
+ PKIX_PL_OcspResponse *response,
+ PKIX_Boolean *pPassed,
+ SECErrorCodes *pReturnCode,
+ void *plContext)
+{
+
+ PKIX_ENTER(OCSPRESPONSE, "PKIX_PL_OcspResponse_Decode");
+ PKIX_NULLCHECK_TWO(response, response->encodedResponse);
+
+ response->nssOCSPResponse =
+ CERT_DecodeOCSPResponse(response->encodedResponse);
+
+ if (response->nssOCSPResponse != NULL) {
+ *pPassed = PKIX_TRUE;
+ *pReturnCode = 0;
+ } else {
+ *pPassed = PKIX_FALSE;
+ *pReturnCode = PORT_GetError();
+ }
+
+ PKIX_RETURN(OCSPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_GetStatus
+ * DESCRIPTION:
+ *
+ * This function checks the response status of the OcspResponse pointed to
+ * by "response", storing PKIX_TRUE at "pPassed" if the responder understood
+ * the request and considered it valid, and PKIX_FALSE otherwise.
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the OcspResponse whose status is to be retrieved. Must
+ * be non-NULL.
+ * "pPassed"
+ * Address at which the Boolean result is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an OcspResponse Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+
+PKIX_Error *
+pkix_pl_OcspResponse_GetStatus(
+ PKIX_PL_OcspResponse *response,
+ PKIX_Boolean *pPassed,
+ SECErrorCodes *pReturnCode,
+ void *plContext)
+{
+ SECStatus rv = SECFailure;
+
+ PKIX_ENTER(OCSPRESPONSE, "PKIX_PL_OcspResponse_GetStatus");
+ PKIX_NULLCHECK_FOUR(response, response->nssOCSPResponse, pPassed, pReturnCode);
+
+ rv = CERT_GetOCSPResponseStatus(response->nssOCSPResponse);
+
+ if (rv == SECSuccess) {
+ *pPassed = PKIX_TRUE;
+ *pReturnCode = 0;
+ } else {
+ *pPassed = PKIX_FALSE;
+ *pReturnCode = PORT_GetError();
+ }
+
+ PKIX_RETURN(OCSPRESPONSE);
+}
+
+
+static PKIX_Error*
+pkix_pl_OcspResponse_VerifyResponse(
+ PKIX_PL_OcspResponse *response,
+ PKIX_ProcessingParams *procParams,
+ SECCertUsage certUsage,
+ void **state,
+ PKIX_BuildResult **buildResult,
+ void **pNBIOContext,
+ void *plContext)
+{
+ SECStatus rv = SECFailure;
+
+ PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_VerifyResponse");
+
+ if (response->verifyFcn != NULL) {
+ void *lplContext = NULL;
+
+ PKIX_CHECK(
+ PKIX_PL_NssContext_Create(((SECCertificateUsage)1) << certUsage,
+ PKIX_FALSE, NULL, &lplContext),
+ PKIX_NSSCONTEXTCREATEFAILED);
+
+ PKIX_CHECK(
+ (response->verifyFcn)((PKIX_PL_Object*)response->pkixSignerCert,
+ NULL, response->producedAtDate,
+ procParams, pNBIOContext,
+ state, buildResult,
+ NULL, lplContext),
+ PKIX_CERTVERIFYKEYUSAGEFAILED);
+ rv = SECSuccess;
+ } else {
+ rv = CERT_VerifyCert(response->handle, response->signerCert, PKIX_TRUE,
+ certUsage, response->producedAt, NULL, NULL);
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_CERTVERIFYKEYUSAGEFAILED);
+ }
+ }
+
+cleanup:
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
+ }
+
+ PKIX_RETURN(OCSPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_VerifySignature
+ * DESCRIPTION:
+ *
+ * This function verifies the ocspResponse signature field in the OcspResponse
+ * pointed to by "response", storing PKIX_TRUE at "pPassed" if verification
+ * is successful and PKIX_FALSE otherwise. If verification is unsuccessful an
+ * error code (an enumeration of type SECErrorCodes) is stored at *pReturnCode.
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the OcspResponse whose signature field is to be
+ * retrieved. Must be non-NULL.
+ * "cert"
+ * The address of the Cert for which the OCSP query was made. Must be
+ * non-NULL.
+ * "procParams"
+ * Address of ProcessingParams used to initialize the ExpirationChecker
+ * and TargetCertChecker. Must be non-NULL.
+ * "pPassed"
+ * Address at which the Boolean result is stored. Must be non-NULL.
+ * "pNBIOContext"
+ * Address at which the NBIOContext is stored indicating whether the
+ * checking is complete. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an OcspResponse Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_OcspResponse_VerifySignature(
+ PKIX_PL_OcspResponse *response,
+ PKIX_PL_Cert *cert,
+ PKIX_ProcessingParams *procParams,
+ PKIX_Boolean *pPassed,
+ void **pNBIOContext,
+ void *plContext)
+{
+ SECStatus rv = SECFailure;
+ CERTOCSPResponse *nssOCSPResponse = NULL;
+ CERTCertificate *issuerCert = NULL;
+ PKIX_BuildResult *buildResult = NULL;
+ void *nbio = NULL;
+ void *state = NULL;
+
+ ocspSignature *signature = NULL;
+ ocspResponseData *tbsData = NULL;
+ SECItem *tbsResponseDataDER = NULL;
+
+
+ PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_VerifySignature");
+ PKIX_NULLCHECK_FOUR(response, cert, pPassed, pNBIOContext);
+
+ nbio = *pNBIOContext;
+ *pNBIOContext = NULL;
+
+ nssOCSPResponse = response->nssOCSPResponse;
+ if (nssOCSPResponse == NULL) {
+ PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
+ goto cleanup;
+ }
+
+ tbsData =
+ ocsp_GetResponseData(nssOCSPResponse, &tbsResponseDataDER);
+
+ signature = ocsp_GetResponseSignature(nssOCSPResponse);
+
+
+ /* Are we resuming after a WOULDBLOCK response? */
+ if (nbio == NULL) {
+ /* No, this is a new query */
+
+ issuerCert = CERT_FindCertIssuer(cert->nssCert, PR_Now(),
+ certUsageAnyCA);
+
+ /*
+ * If this signature has already gone through verification,
+ * just return the cached result.
+ */
+ if (signature->wasChecked) {
+ if (signature->status == SECSuccess) {
+ response->signerCert =
+ CERT_DupCertificate(signature->cert);
+ } else {
+ PORT_SetError(signature->failureReason);
+ goto cleanup;
+ }
+ }
+
+ response->signerCert =
+ ocsp_GetSignerCertificate(response->handle, tbsData,
+ signature, issuerCert);
+
+ if (response->signerCert == NULL) {
+ if (PORT_GetError() == SEC_ERROR_UNKNOWN_CERT) {
+ /* Make the error a little more specific. */
+ PORT_SetError(SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
+ }
+ goto cleanup;
+ }
+ PKIX_CHECK(
+ PKIX_PL_Cert_CreateFromCERTCertificate(response->signerCert,
+ &(response->pkixSignerCert),
+ plContext),
+ PKIX_CERTCREATEWITHNSSCERTFAILED);
+
+ /*
+ * 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. Maybe a subsequent call will
+ * have better luck.
+ */
+ signature->wasChecked = PR_TRUE;
+
+ /*
+ * We are about to verify the signer certificate; we need to
+ * specify *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(&response->producedAt,
+ &tbsData->producedAt);
+ if (rv != SECSuccess) {
+ PORT_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
+ goto cleanup;
+ }
+
+ /*
+ * We need producedAtDate and pkixSignerCert if we are calling a
+ * user-supplied verification function. Let's put their
+ * creation before the code that gets repeated when
+ * non-blocking I/O is used.
+ */
+
+ PKIX_CHECK(
+ pkix_pl_Date_CreateFromPRTime((PRTime)response->producedAt,
+ &(response->producedAtDate),
+ plContext),
+ PKIX_DATECREATEFROMPRTIMEFAILED);
+
+ }
+
+ /*
+ * Just because we have a cert does not mean it is any good; check
+ * it for validity, trust and usage. Use the caller-supplied
+ * verification function, if one was supplied.
+ */
+ if (ocsp_CertIsOCSPDefaultResponder(response->handle,
+ response->signerCert)) {
+ rv = SECSuccess;
+ } else {
+ SECCertUsage certUsage;
+ if (CERT_IsCACert(response->signerCert, NULL)) {
+ certUsage = certUsageAnyCA;
+ } else {
+ certUsage = certUsageStatusResponder;
+ }
+ PKIX_CHECK_ONLY_FATAL(
+ pkix_pl_OcspResponse_VerifyResponse(response, procParams,
+ certUsage, &state,
+ &buildResult, &nbio,
+ plContext),
+ PKIX_CERTVERIFYKEYUSAGEFAILED);
+ if (pkixTempErrorReceived) {
+ rv = SECFailure;
+ goto cleanup;
+ }
+ if (nbio != NULL) {
+ *pNBIOContext = nbio;
+ goto cleanup;
+ }
+ }
+
+ rv = ocsp_VerifyResponseSignature(response->signerCert, signature,
+ tbsResponseDataDER, NULL);
+
+cleanup:
+ if (rv == SECSuccess) {
+ *pPassed = PKIX_TRUE;
+ } else {
+ *pPassed = PKIX_FALSE;
+ }
+
+ if (signature) {
+ if (signature->wasChecked) {
+ signature->status = rv;
+ }
+
+ if (rv != SECSuccess) {
+ signature->failureReason = PORT_GetError();
+ if (response->signerCert != NULL) {
+ CERT_DestroyCertificate(response->signerCert);
+ response->signerCert = NULL;
+ }
+ } else {
+ /* Save signer's certificate in signature. */
+ signature->cert = CERT_DupCertificate(response->signerCert);
+ }
+ }
+
+ if (issuerCert)
+ CERT_DestroyCertificate(issuerCert);
+
+ PKIX_RETURN(OCSPRESPONSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_OcspResponse_GetStatusForCert
+ * DESCRIPTION:
+ *
+ * This function checks the revocation status of the Cert for which the
+ * OcspResponse was obtained, storing PKIX_TRUE at "pPassed" if the Cert has
+ * not been revoked and PKIX_FALSE otherwise.
+ *
+ * PARAMETERS
+ * "response"
+ * The address of the OcspResponse whose certificate status is to be
+ * retrieved. Must be non-NULL.
+ * "pPassed"
+ * Address at which the Boolean result is stored. Must be non-NULL.
+ * "pReturnCode"
+ * Address at which the SECErrorCodes result is stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an OcspResponse Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_OcspResponse_GetStatusForCert(
+ PKIX_PL_OcspCertID *cid,
+ PKIX_PL_OcspResponse *response,
+ PKIX_Boolean allowCachingOfFailures,
+ PKIX_PL_Date *validity,
+ PKIX_Boolean *pPassed,
+ SECErrorCodes *pReturnCode,
+ void *plContext)
+{
+ PRTime time = 0;
+ SECStatus rv = SECFailure;
+ CERTOCSPSingleResponse *single = NULL;
+
+ PKIX_ENTER(OCSPRESPONSE, "pkix_pl_OcspResponse_GetStatusForCert");
+ PKIX_NULLCHECK_THREE(response, pPassed, pReturnCode);
+
+ /*
+ * It is an error to call this function except following a successful
+ * return from pkix_pl_OcspResponse_VerifySignature, which would have
+ * set response->signerCert.
+ */
+ PKIX_NULLCHECK_TWO(response->signerCert, response->request);
+ PKIX_NULLCHECK_TWO(cid, cid->certID);
+
+ if (validity != NULL) {
+ PKIX_Error *er = pkix_pl_Date_GetPRTime(validity, &time, plContext);
+ PKIX_DECREF(er);
+ }
+ if (!time) {
+ time = PR_Now();
+ }
+
+ rv = ocsp_GetVerifiedSingleResponseForCertID(response->handle,
+ response->nssOCSPResponse,
+ cid->certID,
+ response->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_CertHasGoodStatus(single->certStatus, time);
+ }
+
+ if (rv == SECSuccess || allowCachingOfFailures) {
+ /* allowed to update the cache */
+ PRBool certIDWasConsumed = PR_FALSE;
+
+ if (single) {
+ ocsp_CacheSingleResponse(cid->certID,single,
+ &certIDWasConsumed);
+ } else {
+ cert_RememberOCSPProcessingFailure(cid->certID,
+ &certIDWasConsumed);
+ }
+
+ if (certIDWasConsumed) {
+ cid->certID = NULL;
+ }
+ }
+
+ if (rv == SECSuccess) {
+ *pPassed = PKIX_TRUE;
+ *pReturnCode = 0;
+ } else {
+ *pPassed = PKIX_FALSE;
+ *pReturnCode = PORT_GetError();
+ }
+
+ PKIX_RETURN(OCSPRESPONSE);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.h
new file mode 100644
index 000000000..dcf88c960
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_ocspresponse.h
@@ -0,0 +1,106 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_ocspresponse.h
+ *
+ * OcspResponse Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_OCSPRESPONSE_H
+#define _PKIX_PL_OCSPRESPONSE_H
+
+#include "pkix_pl_common.h"
+#include "pkix_pl_ocspcertid.h"
+#include "hasht.h"
+#include "cryptohi.h"
+#include "ocspti.h"
+#include "ocspi.h"
+#include "plbase64.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define MAX_OCSP_RESPONSE_LEN (64*1024)
+
+struct PKIX_PL_OcspResponseStruct{
+ PLArenaPool *arena;
+ const PKIX_PL_OcspRequest *request;
+ const SEC_HttpClientFcn *httpClient;
+ SEC_HTTP_SERVER_SESSION serverSession;
+ SEC_HTTP_REQUEST_SESSION sessionRequest;
+ PKIX_PL_VerifyCallback verifyFcn;
+ SECItem *encodedResponse;
+ CERTCertDBHandle *handle;
+ PRTime producedAt;
+ PKIX_PL_Date *producedAtDate;
+ PKIX_PL_Cert *pkixSignerCert;
+ CERTOCSPResponse *nssOCSPResponse;
+ CERTCertificate *signerCert;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_OcspResponse_RegisterSelf(void *plContext);
+
+PKIX_Error *
+pkix_pl_OcspResponse_Create(
+ PKIX_PL_OcspRequest *request,
+ const char *httpMechanism,
+ void *responder,
+ PKIX_PL_VerifyCallback verifyFcn,
+ void **pNBIOContext,
+ PKIX_PL_OcspResponse **pResponse,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_OcspResponse_Decode(
+ PKIX_PL_OcspResponse *response,
+ PKIX_Boolean *passed,
+ SECErrorCodes *pReturnCode,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_OcspResponse_GetStatus(
+ PKIX_PL_OcspResponse *response,
+ PKIX_Boolean *passed,
+ SECErrorCodes *pReturnCode,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_OcspResponse_VerifySignature(
+ PKIX_PL_OcspResponse *response,
+ PKIX_PL_Cert *cert,
+ PKIX_ProcessingParams *procParams,
+ PKIX_Boolean *pPassed,
+ void **pNBIOContext,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_OcspResponse_GetStatusForCert(
+ PKIX_PL_OcspCertID *cid,
+ PKIX_PL_OcspResponse *response,
+ PKIX_Boolean allowCachingOfFailures,
+ PKIX_PL_Date *validity,
+ PKIX_Boolean *pPassed,
+ SECErrorCodes *pReturnCode,
+ void *plContext);
+
+PKIX_Error *
+PKIX_PL_OcspResponse_UseBuildChain(
+ PKIX_PL_Cert *signerCert,
+ PKIX_PL_Date *producedAt,
+ PKIX_ProcessingParams *procParams,
+ void **pNBIOContext,
+ void **pState,
+ PKIX_BuildResult **pBuildResult,
+ PKIX_VerifyNode **pVerifyTree,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_OCSPRESPONSE_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.c
new file mode 100644
index 000000000..2dfe9a9c2
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.c
@@ -0,0 +1,489 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_publickey.c
+ *
+ * Certificate Object Functions
+ *
+ */
+
+#include "pkix_pl_publickey.h"
+
+/* --Private-Cert-Functions------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_PublicKey_ToString_Helper
+ * DESCRIPTION:
+ *
+ * Helper function that creates a string representation of the PublicKey
+ * pointed to by "pkixPubKey" and stores it at "pString".
+ *
+ * PARAMETERS
+ * "pkixPubKey"
+ * Address of PublicKey whose string representation is desired.
+ * Must be non-NULL.
+ * "pString"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a PublicKey Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_PublicKey_ToString_Helper(
+ PKIX_PL_PublicKey *pkixPubKey,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ SECAlgorithmID algorithm;
+ SECOidTag pubKeyTag;
+ char *asciiOID = NULL;
+ PKIX_Boolean freeAsciiOID = PKIX_FALSE;
+ SECItem oidBytes;
+
+ PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_ToString_Helper");
+ PKIX_NULLCHECK_THREE(pkixPubKey, pkixPubKey->nssSPKI, pString);
+
+ /*
+ * XXX for now, we print out public key algorithm's
+ * description - add params and bytes later
+ */
+
+ /*
+ * If the algorithm OID is known to NSS,
+ * we print out the ASCII description that is
+ * registered with NSS. Otherwise, if unknown,
+ * we print out the OID numbers (eg. "1.2.840.3")
+ */
+
+ algorithm = pkixPubKey->nssSPKI->algorithm;
+
+ PKIX_PUBLICKEY_DEBUG("\t\tCalling SECOID_GetAlgorithmTag).\n");
+ pubKeyTag = SECOID_GetAlgorithmTag(&algorithm);
+ if (pubKeyTag != SEC_OID_UNKNOWN){
+ PKIX_PUBLICKEY_DEBUG
+ ("\t\tCalling SECOID_FindOIDTagDescription).\n");
+ asciiOID = (char *)SECOID_FindOIDTagDescription(pubKeyTag);
+ if (!asciiOID){
+ PKIX_ERROR(PKIX_SECOIDFINDOIDTAGDESCRIPTIONFAILED);
+ }
+ } else { /* pubKeyTag == SEC_OID_UNKNOWN */
+ oidBytes = algorithm.algorithm;
+ PKIX_CHECK(pkix_pl_oidBytes2Ascii
+ (&oidBytes, &asciiOID, plContext),
+ PKIX_OIDBYTES2ASCIIFAILED);
+ freeAsciiOID = PKIX_TRUE;
+ }
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, (void *)asciiOID, 0, pString, plContext),
+ PKIX_UNABLETOCREATEPSTRING);
+
+cleanup:
+
+ /*
+ * we only free asciiOID if it was malloc'ed by pkix_pl_oidBytes2Ascii
+ */
+ if (freeAsciiOID){
+ PKIX_FREE(asciiOID);
+ }
+
+ PKIX_RETURN(PUBLICKEY);
+}
+
+/*
+ * FUNCTION: pkix_pl_DestroySPKI
+ * DESCRIPTION:
+ * Frees all memory associated with the CERTSubjectPublicKeyInfo pointed to
+ * by "nssSPKI".
+ * PARAMETERS
+ * "nssSPKI"
+ * Address of CERTSubjectPublicKeyInfo. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an Object Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_DestroySPKI(
+ CERTSubjectPublicKeyInfo *nssSPKI,
+ void *plContext)
+{
+ PKIX_ENTER(PUBLICKEY, "pkix_pl_DestroySPKI");
+
+ PKIX_NULLCHECK_ONE(nssSPKI);
+
+ PKIX_PUBLICKEY_DEBUG("\t\tCalling SECOID_DestroyAlgorithmID).\n");
+ SECOID_DestroyAlgorithmID(&nssSPKI->algorithm, PKIX_FALSE);
+
+ PKIX_PUBLICKEY_DEBUG("\t\tCalling SECITEM_FreeItem).\n");
+ SECITEM_FreeItem(&nssSPKI->subjectPublicKey, PKIX_FALSE);
+
+ PKIX_RETURN(PUBLICKEY);
+}
+
+/*
+ * FUNCTION: pkix_pl_PublicKey_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_PublicKey_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_PublicKey *pubKey = NULL;
+
+ PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_Destroy");
+
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_PUBLICKEY_TYPE, plContext),
+ PKIX_OBJECTNOTPUBLICKEY);
+
+ pubKey = (PKIX_PL_PublicKey *)object;
+
+ if (pubKey->nssSPKI) {
+
+ PKIX_CHECK(pkix_pl_DestroySPKI(pubKey->nssSPKI, plContext),
+ PKIX_DESTROYSPKIFAILED);
+
+ PKIX_FREE(pubKey->nssSPKI);
+ }
+
+cleanup:
+
+ PKIX_RETURN(PUBLICKEY);
+}
+
+/*
+ * FUNCTION: pkix_pl_PublicKey_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_PublicKey_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_PublicKey *pkixPubKey = NULL;
+ PKIX_PL_String *pubKeyString = NULL;
+
+ PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_toString");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_PUBLICKEY_TYPE, plContext),
+ PKIX_OBJECTNOTPUBLICKEY);
+
+ pkixPubKey = (PKIX_PL_PublicKey *)object;
+
+ PKIX_CHECK(pkix_pl_PublicKey_ToString_Helper
+ (pkixPubKey, &pubKeyString, plContext),
+ PKIX_PUBLICKEYTOSTRINGHELPERFAILED);
+
+ *pString = pubKeyString;
+
+cleanup:
+
+ PKIX_RETURN(PUBLICKEY);
+}
+
+/*
+ * FUNCTION: pkix_pl_PublicKey_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_PublicKey_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_PublicKey *pkixPubKey = NULL;
+ SECItem algOID;
+ SECItem algParams;
+ SECItem nssPubKey;
+ PKIX_UInt32 algOIDHash;
+ PKIX_UInt32 algParamsHash;
+ PKIX_UInt32 pubKeyHash;
+
+ PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_PUBLICKEY_TYPE, plContext),
+ PKIX_OBJECTNOTPUBLICKEY);
+
+ pkixPubKey = (PKIX_PL_PublicKey *)object;
+
+ PKIX_NULLCHECK_ONE(pkixPubKey->nssSPKI);
+
+ algOID = pkixPubKey->nssSPKI->algorithm.algorithm;
+ algParams = pkixPubKey->nssSPKI->algorithm.parameters;
+ nssPubKey = pkixPubKey->nssSPKI->subjectPublicKey;
+
+ PKIX_CHECK(pkix_hash
+ (algOID.data, algOID.len, &algOIDHash, plContext),
+ PKIX_HASHFAILED);
+
+ PKIX_CHECK(pkix_hash
+ (algParams.data, algParams.len, &algParamsHash, plContext),
+ PKIX_HASHFAILED);
+
+ PKIX_CHECK(pkix_hash
+ (nssPubKey.data, nssPubKey.len, &pubKeyHash, plContext),
+ PKIX_HASHFAILED);
+
+ *pHashcode = pubKeyHash;
+
+cleanup:
+
+ PKIX_RETURN(PUBLICKEY);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_PublicKey_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_PublicKey_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_PL_PublicKey *firstPKIXPubKey = NULL;
+ PKIX_PL_PublicKey *secondPKIXPubKey = NULL;
+ CERTSubjectPublicKeyInfo *firstSPKI = NULL;
+ CERTSubjectPublicKeyInfo *secondSPKI = NULL;
+ SECComparison cmpResult;
+ PKIX_UInt32 secondType;
+
+ PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ /* test that firstObject is a PublicKey */
+ PKIX_CHECK(pkix_CheckType(firstObject, PKIX_PUBLICKEY_TYPE, plContext),
+ PKIX_FIRSTOBJECTNOTPUBLICKEY);
+
+ /*
+ * Since we know firstObject is a PublicKey, if both references are
+ * identical, they must be equal
+ */
+ if (firstObject == secondObject){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondObject isn't a PublicKey, we don't throw an error.
+ * We simply return a Boolean result of FALSE
+ */
+ *pResult = PKIX_FALSE;
+ PKIX_CHECK(PKIX_PL_Object_GetType
+ (secondObject, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+ if (secondType != PKIX_PUBLICKEY_TYPE) goto cleanup;
+
+ firstPKIXPubKey = ((PKIX_PL_PublicKey *)firstObject);
+ secondPKIXPubKey = (PKIX_PL_PublicKey *)secondObject;
+
+ firstSPKI = firstPKIXPubKey->nssSPKI;
+ secondSPKI = secondPKIXPubKey->nssSPKI;
+
+ PKIX_NULLCHECK_TWO(firstSPKI, secondSPKI);
+
+ PKIX_PL_NSSCALLRV(PUBLICKEY, cmpResult, SECOID_CompareAlgorithmID,
+ (&firstSPKI->algorithm, &secondSPKI->algorithm));
+
+ if (cmpResult == SECEqual){
+ PKIX_PUBLICKEY_DEBUG("\t\tCalling SECITEM_CompareItem).\n");
+ cmpResult = SECITEM_CompareItem
+ (&firstSPKI->subjectPublicKey,
+ &secondSPKI->subjectPublicKey);
+ }
+
+ *pResult = (cmpResult == SECEqual)?PKIX_TRUE:PKIX_FALSE;
+
+cleanup:
+
+ PKIX_RETURN(PUBLICKEY);
+}
+
+/*
+ * FUNCTION: pkix_pl_PublicKey_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_PUBLICKEY_TYPE and its related functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_PublicKey_RegisterSelf(void *plContext)
+{
+
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(PUBLICKEY, "pkix_pl_PublicKey_RegisterSelf");
+
+ entry.description = "PublicKey";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_PublicKey);
+ entry.destructor = pkix_pl_PublicKey_Destroy;
+ entry.equalsFunction = pkix_pl_PublicKey_Equals;
+ entry.hashcodeFunction = pkix_pl_PublicKey_Hashcode;
+ entry.toStringFunction = pkix_pl_PublicKey_ToString;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+ systemClasses[PKIX_PUBLICKEY_TYPE] = entry;
+
+ PKIX_RETURN(PUBLICKEY);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_PublicKey_NeedsDSAParameters
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_PublicKey_NeedsDSAParameters(
+ PKIX_PL_PublicKey *pubKey,
+ PKIX_Boolean *pNeedsParams,
+ void *plContext)
+{
+ CERTSubjectPublicKeyInfo *nssSPKI = NULL;
+ KeyType pubKeyType;
+ PKIX_Boolean needsParams = PKIX_FALSE;
+
+ PKIX_ENTER(PUBLICKEY, "PKIX_PL_PublicKey_NeedsDSAParameters");
+ PKIX_NULLCHECK_TWO(pubKey, pNeedsParams);
+
+ nssSPKI = pubKey->nssSPKI;
+
+ PKIX_PUBLICKEY_DEBUG("\t\tCalling CERT_GetCertKeyType).\n");
+ pubKeyType = CERT_GetCertKeyType(nssSPKI);
+ if (!pubKeyType){
+ PKIX_ERROR(PKIX_PUBKEYTYPENULLKEY);
+ }
+
+ if ((pubKeyType == dsaKey) &&
+ (nssSPKI->algorithm.parameters.len == 0)){
+ needsParams = PKIX_TRUE;
+ }
+
+ *pNeedsParams = needsParams;
+
+cleanup:
+
+ PKIX_RETURN(PUBLICKEY);
+}
+
+/*
+ * FUNCTION: PKIX_PL_PublicKey_MakeInheritedDSAPublicKey
+ * (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_PublicKey_MakeInheritedDSAPublicKey(
+ PKIX_PL_PublicKey *firstKey,
+ PKIX_PL_PublicKey *secondKey,
+ PKIX_PL_PublicKey **pResultKey,
+ void *plContext)
+{
+ CERTSubjectPublicKeyInfo *firstSPKI = NULL;
+ CERTSubjectPublicKeyInfo *secondSPKI = NULL;
+ CERTSubjectPublicKeyInfo *thirdSPKI = NULL;
+ PKIX_PL_PublicKey *resultKey = NULL;
+ KeyType firstPubKeyType;
+ KeyType secondPubKeyType;
+ SECStatus rv;
+
+ PKIX_ENTER(PUBLICKEY, "PKIX_PL_PublicKey_MakeInheritedDSAPublicKey");
+ PKIX_NULLCHECK_THREE(firstKey, secondKey, pResultKey);
+ PKIX_NULLCHECK_TWO(firstKey->nssSPKI, secondKey->nssSPKI);
+
+ firstSPKI = firstKey->nssSPKI;
+ secondSPKI = secondKey->nssSPKI;
+
+ PKIX_PUBLICKEY_DEBUG("\t\tCalling CERT_GetCertKeyType).\n");
+ firstPubKeyType = CERT_GetCertKeyType(firstSPKI);
+ if (!firstPubKeyType){
+ PKIX_ERROR(PKIX_FIRSTPUBKEYTYPENULLKEY);
+ }
+
+ PKIX_PUBLICKEY_DEBUG("\t\tCalling CERT_GetCertKeyType).\n");
+ secondPubKeyType = CERT_GetCertKeyType(secondSPKI);
+ if (!secondPubKeyType){
+ PKIX_ERROR(PKIX_SECONDPUBKEYTYPENULLKEY);
+ }
+
+ if ((firstPubKeyType == dsaKey) &&
+ (firstSPKI->algorithm.parameters.len == 0)){
+ if (secondPubKeyType != dsaKey) {
+ PKIX_ERROR(PKIX_SECONDKEYNOTDSAPUBLICKEY);
+ } else if (secondSPKI->algorithm.parameters.len == 0) {
+ PKIX_ERROR
+ (PKIX_SECONDKEYDSAPUBLICKEY);
+ } else {
+ PKIX_CHECK(PKIX_PL_Calloc
+ (1,
+ sizeof (CERTSubjectPublicKeyInfo),
+ (void **)&thirdSPKI,
+ plContext),
+ PKIX_CALLOCFAILED);
+
+ PKIX_PUBLICKEY_DEBUG
+ ("\t\tCalling"
+ "SECKEY_CopySubjectPublicKeyInfo).\n");
+ rv = SECKEY_CopySubjectPublicKeyInfo
+ (NULL, thirdSPKI, firstSPKI);
+ if (rv != SECSuccess) {
+ PKIX_ERROR
+ (PKIX_SECKEYCOPYSUBJECTPUBLICKEYINFOFAILED);
+ }
+
+ PKIX_PUBLICKEY_DEBUG
+ ("\t\tCalling SECITEM_CopyItem).\n");
+ rv = SECITEM_CopyItem(NULL,
+ &thirdSPKI->algorithm.parameters,
+ &secondSPKI->algorithm.parameters);
+
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ /* create a PKIX_PL_PublicKey object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_PUBLICKEY_TYPE,
+ sizeof (PKIX_PL_PublicKey),
+ (PKIX_PL_Object **)&resultKey,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ /* populate the SPKI field */
+ resultKey->nssSPKI = thirdSPKI;
+ *pResultKey = resultKey;
+ }
+ } else {
+ *pResultKey = NULL;
+ }
+
+cleanup:
+
+ if (thirdSPKI && PKIX_ERROR_RECEIVED){
+ PKIX_CHECK(pkix_pl_DestroySPKI(thirdSPKI, plContext),
+ PKIX_DESTROYSPKIFAILED);
+ PKIX_FREE(thirdSPKI);
+ }
+
+ PKIX_RETURN(PUBLICKEY);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.h
new file mode 100644
index 000000000..8918859d2
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_publickey.h
@@ -0,0 +1,38 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_publickey.h
+ *
+ * Public Key Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_PUBLICKEY_H
+#define _PKIX_PL_PUBLICKEY_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_PublicKeyStruct {
+ CERTSubjectPublicKeyInfo *nssSPKI;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_PublicKey_RegisterSelf(void *plContext);
+
+PKIX_Error *
+PKIX_PL_PublicKey_NeedsDSAParameters(
+ PKIX_PL_PublicKey *pubKey,
+ PKIX_Boolean *pNeedsParams,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_PUBLICKEY_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.c b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.c
new file mode 100644
index 000000000..e37439cf0
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.c
@@ -0,0 +1,667 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_x500name.c
+ *
+ * X500Name Object Functions
+ *
+ */
+
+#include "pkix_pl_x500name.h"
+
+/* --Private-X500Name-Functions------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_X500Name_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_X500Name_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_X500Name *name = NULL;
+
+ PKIX_ENTER(X500NAME, "pkix_pl_X500Name_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_X500NAME_TYPE, plContext),
+ PKIX_OBJECTNOTANX500NAME);
+
+ name = (PKIX_PL_X500Name *)object;
+
+ /* PORT_FreeArena will destroy arena, and, allocated on it, CERTName
+ * and SECItem */
+ if (name->arena) {
+ PORT_FreeArena(name->arena, PR_FALSE);
+ name->arena = NULL;
+ }
+
+cleanup:
+
+ PKIX_RETURN(X500NAME);
+}
+
+/*
+ * FUNCTION: pkix_pl_X500Name_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_X500Name_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_X500Name *name = NULL;
+ char *string = NULL;
+ PKIX_UInt32 strLength = 0;
+
+ PKIX_ENTER(X500NAME, "pkix_pl_X500Name_toString");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_X500NAME_TYPE, plContext),
+ PKIX_OBJECTNOTANX500NAME);
+
+ name = (PKIX_PL_X500Name *)object;
+ string = CERT_NameToAscii(&name->nssDN);
+ if (!string){
+ PKIX_ERROR(PKIX_CERTNAMETOASCIIFAILED);
+ }
+ strLength = PL_strlen(string);
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, string, strLength, pString, plContext),
+ PKIX_STRINGCREATEFAILED);
+
+cleanup:
+
+ PKIX_RETURN(X500NAME);
+}
+
+/*
+ * FUNCTION: pkix_pl_X500Name_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_X500Name_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_X500Name *name = NULL;
+ SECItem *derBytes = NULL;
+ PKIX_UInt32 nameHash;
+
+ PKIX_ENTER(X500NAME, "pkix_pl_X500Name_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_X500NAME_TYPE, plContext),
+ PKIX_OBJECTNOTANX500NAME);
+
+ name = (PKIX_PL_X500Name *)object;
+
+ /* we hash over the bytes in the DER encoding */
+
+ derBytes = &name->derName;
+
+ PKIX_CHECK(pkix_hash
+ (derBytes->data, derBytes->len, &nameHash, plContext),
+ PKIX_HASHFAILED);
+
+ *pHashcode = nameHash;
+
+cleanup:
+
+ PKIX_RETURN(X500NAME);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_X500Name_Equals
+ * (see comments for PKIX_PL_Equals_Callback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_X500Name_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_UInt32 secondType;
+
+ PKIX_ENTER(X500NAME, "pkix_pl_X500Name_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ /* test that firstObject is an X500Name */
+ PKIX_CHECK(pkix_CheckType(firstObject, PKIX_X500NAME_TYPE, plContext),
+ PKIX_FIRSTOBJECTARGUMENTNOTANX500NAME);
+
+ /*
+ * Since we know firstObject is an X500Name, if both references are
+ * identical, they must be equal
+ */
+ if (firstObject == secondObject){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ /*
+ * If secondObject isn't an X500Name, we don't throw an error.
+ * We simply return a Boolean result of FALSE
+ */
+ *pResult = PKIX_FALSE;
+ PKIX_CHECK(PKIX_PL_Object_GetType
+ (secondObject, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+ if (secondType != PKIX_X500NAME_TYPE) goto cleanup;
+
+ PKIX_CHECK(
+ PKIX_PL_X500Name_Match((PKIX_PL_X500Name *)firstObject,
+ (PKIX_PL_X500Name *)secondObject,
+ pResult, plContext),
+ PKIX_X500NAMEMATCHFAILED);
+
+cleanup:
+
+ PKIX_RETURN(X500NAME);
+}
+
+/*
+ * FUNCTION: pkix_pl_X500Name_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_X500NAME_TYPE and its related functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_X500Name_RegisterSelf(void *plContext)
+{
+
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(X500NAME, "pkix_pl_X500Name_RegisterSelf");
+
+ entry.description = "X500Name";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_X500Name);
+ entry.destructor = pkix_pl_X500Name_Destroy;
+ entry.equalsFunction = pkix_pl_X500Name_Equals;
+ entry.hashcodeFunction = pkix_pl_X500Name_Hashcode;
+ entry.toStringFunction = pkix_pl_X500Name_ToString;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_X500NAME_TYPE] = entry;
+
+ PKIX_RETURN(X500NAME);
+}
+
+#ifdef BUILD_LIBPKIX_TESTS
+/*
+ * FUNCTION: pkix_pl_X500Name_CreateFromUtf8
+ *
+ * DESCRIPTION:
+ * Creates an X500Name object from the RFC1485 string representation pointed
+ * to by "stringRep", and stores the result at "pName". If the string cannot
+ * be successfully converted, a non-fatal error is returned.
+ *
+ * NOTE: ifdefed BUILD_LIBPKIX_TESTS function: this function is allowed to be
+ * called only by pkix tests programs.
+ *
+ * PARAMETERS:
+ * "stringRep"
+ * Address of the RFC1485 string to be converted. Must be non-NULL.
+ * "pName"
+ * Address where the X500Name result will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an X500NAME Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_X500Name_CreateFromUtf8(
+ char *stringRep,
+ PKIX_PL_X500Name **pName,
+ void *plContext)
+{
+ PKIX_PL_X500Name *x500Name = NULL;
+ PLArenaPool *arena = NULL;
+ CERTName *nssDN = NULL;
+ SECItem *resultSecItem = NULL;
+
+ PKIX_ENTER(X500NAME, "pkix_pl_X500Name_CreateFromUtf8");
+ PKIX_NULLCHECK_TWO(pName, stringRep);
+
+ nssDN = CERT_AsciiToName(stringRep);
+ if (nssDN == NULL) {
+ PKIX_ERROR(PKIX_COULDNOTCREATENSSDN);
+ }
+
+ arena = nssDN->arena;
+
+ /* create a PKIX_PL_X500Name object */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_X500NAME_TYPE,
+ sizeof (PKIX_PL_X500Name),
+ (PKIX_PL_Object **)&x500Name,
+ plContext),
+ PKIX_COULDNOTCREATEX500NAMEOBJECT);
+
+ /* populate the nssDN field */
+ x500Name->arena = arena;
+ x500Name->nssDN.arena = arena;
+ x500Name->nssDN.rdns = nssDN->rdns;
+
+ resultSecItem =
+ SEC_ASN1EncodeItem(arena, &x500Name->derName, nssDN,
+ CERT_NameTemplate);
+
+ if (resultSecItem == NULL){
+ PKIX_ERROR(PKIX_SECASN1ENCODEITEMFAILED);
+ }
+
+ *pName = x500Name;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ if (x500Name) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object*)x500Name,
+ plContext);
+ } else if (nssDN) {
+ CERT_DestroyName(nssDN);
+ }
+ }
+
+ PKIX_RETURN(X500NAME);
+}
+#endif /* BUILD_LIBPKIX_TESTS */
+
+/*
+ * FUNCTION: pkix_pl_X500Name_GetCERTName
+ *
+ * DESCRIPTION:
+ *
+ * Returns the pointer to CERTName member of X500Name structure.
+ *
+ * Returned pointed should not be freed.2
+ *
+ * PARAMETERS:
+ * "xname"
+ * Address of X500Name whose OrganizationName is to be extracted. Must be
+ * non-NULL.
+ * "pCERTName"
+ * Address where result will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_X500Name_GetCERTName(
+ PKIX_PL_X500Name *xname,
+ CERTName **pCERTName,
+ void *plContext)
+{
+ PKIX_ENTER(X500NAME, "pkix_pl_X500Name_GetCERTName");
+ PKIX_NULLCHECK_TWO(xname, pCERTName);
+
+ *pCERTName = &xname->nssDN;
+
+ PKIX_RETURN(X500NAME);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_X500Name_CreateFromCERTName (see comments in pkix_pl_pki.h)
+ */
+
+PKIX_Error *
+PKIX_PL_X500Name_CreateFromCERTName(
+ SECItem *derName,
+ CERTName *name,
+ PKIX_PL_X500Name **pName,
+ void *plContext)
+{
+ PLArenaPool *arena = NULL;
+ SECStatus rv = SECFailure;
+ PKIX_PL_X500Name *x500Name = NULL;
+
+ PKIX_ENTER(X500NAME, "PKIX_PL_X500Name_CreateFromCERTName");
+ PKIX_NULLCHECK_ONE(pName);
+ if (derName == NULL && name == NULL) {
+ PKIX_ERROR(PKIX_NULLARGUMENT);
+ }
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_X500NAME_TYPE,
+ sizeof (PKIX_PL_X500Name),
+ (PKIX_PL_Object **)&x500Name,
+ plContext),
+ PKIX_COULDNOTCREATEX500NAMEOBJECT);
+
+ x500Name->arena = arena;
+ x500Name->nssDN.arena = NULL;
+
+ if (derName != NULL) {
+ rv = SECITEM_CopyItem(arena, &x500Name->derName, derName);
+ if (rv == SECFailure) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+ }
+
+ if (name != NULL) {
+ rv = CERT_CopyName(arena, &x500Name->nssDN, name);
+ if (rv == SECFailure) {
+ PKIX_ERROR(PKIX_CERTCOPYNAMEFAILED);
+ }
+ } else {
+ rv = SEC_QuickDERDecodeItem(arena, &x500Name->nssDN,
+ CERT_NameTemplate,
+ &x500Name->derName);
+ if (rv == SECFailure) {
+ PKIX_ERROR(PKIX_SECQUICKDERDECODERFAILED);
+ }
+ }
+
+ *pName = x500Name;
+
+cleanup:
+ if (PKIX_ERROR_RECEIVED) {
+ if (x500Name) {
+ PKIX_PL_Object_DecRef((PKIX_PL_Object*)x500Name,
+ plContext);
+ } else if (arena) {
+ PORT_FreeArena(arena, PR_FALSE);
+ }
+ }
+
+ PKIX_RETURN(X500NAME);
+}
+
+#ifdef BUILD_LIBPKIX_TESTS
+/*
+ * FUNCTION: PKIX_PL_X500Name_Create (see comments in pkix_pl_pki.h)
+ *
+ * NOTE: ifdefed BUILD_LIBPKIX_TESTS function: this function is allowed
+ * to be called only by pkix tests programs.
+ */
+PKIX_Error *
+PKIX_PL_X500Name_Create(
+ PKIX_PL_String *stringRep,
+ PKIX_PL_X500Name **pName,
+ void *plContext)
+{
+ char *utf8String = NULL;
+ PKIX_UInt32 utf8Length = 0;
+
+ PKIX_ENTER(X500NAME, "PKIX_PL_X500Name_Create");
+ PKIX_NULLCHECK_TWO(pName, stringRep);
+
+ /*
+ * convert the input PKIX_PL_String to PKIX_UTF8_NULL_TERM.
+ * we need to use this format specifier because
+ * CERT_AsciiToName expects a NULL-terminated UTF8 string.
+ * Since UTF8 allow NUL characters in the middle of the
+ * string, this is buggy. However, as a workaround, using
+ * PKIX_UTF8_NULL_TERM gives us a NULL-terminated UTF8 string.
+ */
+
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ (stringRep,
+ PKIX_UTF8_NULL_TERM,
+ (void **)&utf8String,
+ &utf8Length,
+ plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+
+ PKIX_CHECK(
+ pkix_pl_X500Name_CreateFromUtf8(utf8String,
+ pName, plContext),
+ PKIX_X500NAMECREATEFROMUTF8FAILED);
+
+cleanup:
+ PKIX_FREE(utf8String);
+
+ PKIX_RETURN(X500NAME);
+}
+#endif /* BUILD_LIBPKIX_TESTS */
+
+/*
+ * FUNCTION: PKIX_PL_X500Name_Match (see comments in pkix_pl_pki.h)
+ */
+PKIX_Error *
+PKIX_PL_X500Name_Match(
+ PKIX_PL_X500Name *firstX500Name,
+ PKIX_PL_X500Name *secondX500Name,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ SECItem *firstDerName = NULL;
+ SECItem *secondDerName = NULL;
+ SECComparison cmpResult;
+
+ PKIX_ENTER(X500NAME, "PKIX_PL_X500Name_Match");
+ PKIX_NULLCHECK_THREE(firstX500Name, secondX500Name, pResult);
+
+ if (firstX500Name == secondX500Name){
+ *pResult = PKIX_TRUE;
+ goto cleanup;
+ }
+
+ firstDerName = &firstX500Name->derName;
+ secondDerName = &secondX500Name->derName;
+
+ PKIX_NULLCHECK_TWO(firstDerName->data, secondDerName->data);
+
+ cmpResult = SECITEM_CompareItem(firstDerName, secondDerName);
+ if (cmpResult != SECEqual) {
+ cmpResult = CERT_CompareName(&firstX500Name->nssDN,
+ &secondX500Name->nssDN);
+ }
+
+ *pResult = (cmpResult == SECEqual);
+
+cleanup:
+
+ PKIX_RETURN(X500NAME);
+}
+
+/*
+ * FUNCTION: pkix_pl_X500Name_GetSECName
+ *
+ * DESCRIPTION:
+ * Returns a copy of CERTName DER representation allocated on passed in arena.
+ * If allocation on arena can not be done, NULL is stored at "pSECName".
+ *
+ * PARAMETERS:
+ * "xname"
+ * Address of X500Name whose CERTName flag is to be encoded. Must be
+ * non-NULL.
+ * "arena"
+ * Address of the PLArenaPool to be used in the encoding, and in which
+ * "pSECName" will be allocated. Must be non-NULL.
+ * "pSECName"
+ * Address where result will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_X500Name_GetDERName(
+ PKIX_PL_X500Name *xname,
+ PLArenaPool *arena,
+ SECItem **pDERName,
+ void *plContext)
+{
+ SECItem *derName = NULL;
+
+ PKIX_ENTER(X500NAME, "pkix_pl_X500Name_GetDERName");
+
+ PKIX_NULLCHECK_THREE(xname, arena, pDERName);
+
+ /* Return NULL is X500Name was not created from DER */
+ if (xname->derName.data == NULL) {
+ *pDERName = NULL;
+ goto cleanup;
+ }
+
+ derName = SECITEM_ArenaDupItem(arena, &xname->derName);
+ if (derName == NULL) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ *pDERName = derName;
+cleanup:
+
+ PKIX_RETURN(X500NAME);
+}
+
+/*
+ * FUNCTION: pkix_pl_X500Name_GetCommonName
+ *
+ * DESCRIPTION:
+ * Extracts the CommonName component of the X500Name object pointed to by
+ * "xname", and stores the result at "pCommonName". If the CommonName cannot
+ * be successfully extracted, NULL is stored at "pCommonName".
+ *
+ * The returned string must be freed with PORT_Free.
+ *
+ * PARAMETERS:
+ * "xname"
+ * Address of X500Name whose CommonName is to be extracted. Must be
+ * non-NULL.
+ * "pCommonName"
+ * Address where result will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_X500Name_GetCommonName(
+ PKIX_PL_X500Name *xname,
+ unsigned char **pCommonName,
+ void *plContext)
+{
+ PKIX_ENTER(X500NAME, "pkix_pl_X500Name_GetCommonName");
+ PKIX_NULLCHECK_TWO(xname, pCommonName);
+
+ *pCommonName = (unsigned char *)CERT_GetCommonName(&xname->nssDN);
+
+ PKIX_RETURN(X500NAME);
+}
+
+/*
+ * FUNCTION: pkix_pl_X500Name_GetCountryName
+ *
+ * DESCRIPTION:
+ * Extracts the CountryName component of the X500Name object pointed to by
+ * "xname", and stores the result at "pCountryName". If the CountryName cannot
+ * be successfully extracted, NULL is stored at "pCountryName".
+ *
+ * The returned string must be freed with PORT_Free.
+ *
+ * PARAMETERS:
+ * "xname"
+ * Address of X500Name whose CountryName is to be extracted. Must be
+ * non-NULL.
+ * "pCountryName"
+ * Address where result will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_X500Name_GetCountryName(
+ PKIX_PL_X500Name *xname,
+ unsigned char **pCountryName,
+ void *plContext)
+{
+ PKIX_ENTER(X500NAME, "pkix_pl_X500Name_GetCountryName");
+ PKIX_NULLCHECK_TWO(xname, pCountryName);
+
+ *pCountryName = (unsigned char*)CERT_GetCountryName(&xname->nssDN);
+
+ PKIX_RETURN(X500NAME);
+}
+
+/*
+ * FUNCTION: pkix_pl_X500Name_GetOrgName
+ *
+ * DESCRIPTION:
+ * Extracts the OrganizationName component of the X500Name object pointed to by
+ * "xname", and stores the result at "pOrgName". If the OrganizationName cannot
+ * be successfully extracted, NULL is stored at "pOrgName".
+ *
+ * The returned string must be freed with PORT_Free.
+ *
+ * PARAMETERS:
+ * "xname"
+ * Address of X500Name whose OrganizationName is to be extracted. Must be
+ * non-NULL.
+ * "pOrgName"
+ * Address where result will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ *
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ *
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_X500Name_GetOrgName(
+ PKIX_PL_X500Name *xname,
+ unsigned char **pOrgName,
+ void *plContext)
+{
+ PKIX_ENTER(X500NAME, "pkix_pl_X500Name_GetOrgName");
+ PKIX_NULLCHECK_TWO(xname, pOrgName);
+
+ *pOrgName = (unsigned char*)CERT_GetOrgName(&xname->nssDN);
+
+ PKIX_RETURN(X500NAME);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.h b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.h
new file mode 100644
index 000000000..a62bdb82d
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/pki/pkix_pl_x500name.h
@@ -0,0 +1,74 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_x500name.h
+ *
+ * X500Name Object Type Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_X500NAME_H
+#define _PKIX_PL_X500NAME_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+struct PKIX_PL_X500NameStruct{
+ PLArenaPool *arena; /* X500Name arena. Shared arena with nssDN
+ * and derName */
+ CERTName nssDN;
+ SECItem derName; /* adding DER encoded CERTName to the structure
+ * to avoid unnecessary name encoding when pass
+ * der name to cert finder */
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *pkix_pl_X500Name_RegisterSelf(void *plContext);
+
+PKIX_Error *pkix_pl_X500Name_GetDERName(
+ PKIX_PL_X500Name *xname,
+ PLArenaPool *arena,
+ SECItem **pSECName,
+ void *plContext);
+
+#ifdef BUILD_LIBPKIX_TESTS
+PKIX_Error * pkix_pl_X500Name_CreateFromUtf8(
+ char *stringRep,
+ PKIX_PL_X500Name **pName,
+ void *plContext);
+#endif /* BUILD_LIBPKIX_TESTS */
+
+PKIX_Error *pkix_pl_X500Name_GetCommonName(
+ PKIX_PL_X500Name *xname,
+ unsigned char **pCommonName,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_X500Name_GetCountryName(
+ PKIX_PL_X500Name *xname,
+ unsigned char **pCountryName,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_X500Name_GetOrgName(
+ PKIX_PL_X500Name *xname,
+ unsigned char **pOrgName,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_X500Name_GetCERTName(
+ PKIX_PL_X500Name *xname,
+ CERTName **pCERTName,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_X500NAME_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/Makefile b/security/nss/lib/libpkix/pkix_pl_nss/system/Makefile
new file mode 100755
index 000000000..0fb6c9058
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/Makefile
@@ -0,0 +1,49 @@
+#! gmake
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#######################################################################
+# (1) Include initial platform-independent assignments (MANDATORY). #
+#######################################################################
+
+include manifest.mn
+
+#######################################################################
+# (2) Include "global" configuration information. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/config.mk
+
+#######################################################################
+# (3) Include "component" configuration information. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (4) Include "local" platform-dependent assignments (OPTIONAL). #
+#######################################################################
+
+include config.mk
+
+#######################################################################
+# (5) Execute "global" rules. (OPTIONAL) #
+#######################################################################
+
+include $(CORE_DEPTH)/coreconf/rules.mk
+
+#######################################################################
+# (6) Execute "component" rules. (OPTIONAL) #
+#######################################################################
+
+
+
+#######################################################################
+# (7) Execute "local" rules. (OPTIONAL). #
+#######################################################################
+
+export:: private_export
+
+
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/config.mk b/security/nss/lib/libpkix/pkix_pl_nss/system/config.mk
new file mode 100755
index 000000000..b8c03de79
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/config.mk
@@ -0,0 +1,15 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#
+# Override TARGETS variable so that only static libraries
+# are specifed as dependencies within rules.mk.
+#
+
+TARGETS = $(LIBRARY)
+SHARED_LIBRARY =
+IMPORT_LIBRARY =
+PROGRAM =
+
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/exports.gyp b/security/nss/lib/libpkix/pkix_pl_nss/system/exports.gyp
new file mode 100644
index 000000000..a2f759441
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/exports.gyp
@@ -0,0 +1,37 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+{
+ 'includes': [
+ '../../../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'lib_libpkix_pkix_pl_nss_system_exports',
+ 'type': 'none',
+ 'copies': [
+ {
+ 'files': [
+ 'pkix_pl_bigint.h',
+ 'pkix_pl_bytearray.h',
+ 'pkix_pl_common.h',
+ 'pkix_pl_hashtable.h',
+ 'pkix_pl_lifecycle.h',
+ 'pkix_pl_mem.h',
+ 'pkix_pl_monitorlock.h',
+ 'pkix_pl_mutex.h',
+ 'pkix_pl_object.h',
+ 'pkix_pl_oid.h',
+ 'pkix_pl_primhash.h',
+ 'pkix_pl_rwlock.h',
+ 'pkix_pl_string.h'
+ ],
+ 'destination': '<(nss_private_dist_dir)/<(module)'
+ }
+ ]
+ }
+ ],
+ 'variables': {
+ 'module': 'nss'
+ }
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/manifest.mn b/security/nss/lib/libpkix/pkix_pl_nss/system/manifest.mn
new file mode 100755
index 000000000..82d297992
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/manifest.mn
@@ -0,0 +1,46 @@
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+CORE_DEPTH = ../../../..
+
+EXPORTS = \
+ $(NULL)
+
+PRIVATE_EXPORTS = \
+ pkix_pl_common.h \
+ pkix_pl_mem.h \
+ pkix_pl_object.h \
+ pkix_pl_string.h \
+ pkix_pl_primhash.h \
+ pkix_pl_bigint.h \
+ pkix_pl_mutex.h \
+ pkix_pl_bytearray.h \
+ pkix_pl_lifecycle.h \
+ pkix_pl_oid.h \
+ pkix_pl_hashtable.h \
+ pkix_pl_rwlock.h \
+ pkix_pl_monitorlock.h \
+ $(NULL)
+
+MODULE = nss
+
+CSRCS = \
+ pkix_pl_bigint.c \
+ pkix_pl_bytearray.c \
+ pkix_pl_common.c \
+ pkix_pl_error.c \
+ pkix_pl_hashtable.c \
+ pkix_pl_lifecycle.c \
+ pkix_pl_mem.c \
+ pkix_pl_monitorlock.c \
+ pkix_pl_mutex.c \
+ pkix_pl_object.c \
+ pkix_pl_oid.c \
+ pkix_pl_primhash.c \
+ pkix_pl_rwlock.c \
+ pkix_pl_string.c \
+ $(NULL)
+
+LIBRARY_NAME = pkixsystem
+
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bigint.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bigint.c
new file mode 100755
index 000000000..cd8e15ee4
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bigint.c
@@ -0,0 +1,398 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_bigint.c
+ *
+ * BigInt Object Functions
+ *
+ */
+
+#include "pkix_pl_bigint.h"
+
+/* --Private-Big-Int-Functions------------------------------------ */
+
+/*
+ * FUNCTION: pkix_pl_BigInt_Comparator
+ * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_BigInt_Comparator(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Int32 *pResult,
+ void *plContext)
+{
+ PKIX_PL_BigInt *firstBigInt = NULL;
+ PKIX_PL_BigInt *secondBigInt = NULL;
+ char *firstPtr = NULL;
+ char *secondPtr = NULL;
+ PKIX_UInt32 firstLen, secondLen;
+
+ PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Comparator");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ PKIX_CHECK(pkix_CheckTypes
+ (firstObject, secondObject, PKIX_BIGINT_TYPE, plContext),
+ PKIX_ARGUMENTSNOTBIGINTS);
+
+ /* It's safe to cast */
+ firstBigInt = (PKIX_PL_BigInt*)firstObject;
+ secondBigInt = (PKIX_PL_BigInt*)secondObject;
+
+ *pResult = 0;
+ firstPtr = firstBigInt->dataRep;
+ secondPtr = secondBigInt->dataRep;
+ firstLen = firstBigInt->length;
+ secondLen = secondBigInt->length;
+
+ if (firstLen < secondLen) {
+ *pResult = -1;
+ } else if (firstLen > secondLen) {
+ *pResult = 1;
+ } else if (firstLen == secondLen) {
+ PKIX_BIGINT_DEBUG("\t\tCalling PORT_Memcmp).\n");
+ *pResult = PORT_Memcmp(firstPtr, secondPtr, firstLen);
+ }
+
+cleanup:
+
+ PKIX_RETURN(BIGINT);
+}
+
+/*
+ * FUNCTION: pkix_pl_BigInt_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_BigInt_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_BigInt *bigInt = NULL;
+
+ PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_BIGINT_TYPE, plContext),
+ PKIX_OBJECTNOTBIGINT);
+
+ bigInt = (PKIX_PL_BigInt*)object;
+
+ PKIX_FREE(bigInt->dataRep);
+ bigInt->dataRep = NULL;
+ bigInt->length = 0;
+
+cleanup:
+
+ PKIX_RETURN(BIGINT);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_BigInt_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_BigInt_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_BigInt *bigInt = NULL;
+ char *outputText = NULL;
+ PKIX_UInt32 i, j, lengthChars;
+
+ PKIX_ENTER(BIGINT, "pkix_pl_BigInt_ToString");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_BIGINT_TYPE, plContext),
+ PKIX_OBJECTNOTBIGINT);
+
+ bigInt = (PKIX_PL_BigInt*)object;
+
+ /* number of chars = 2 * (number of bytes) + null terminator */
+ lengthChars = (bigInt->length * 2) + 1;
+
+ PKIX_CHECK(PKIX_PL_Malloc
+ (lengthChars, (void **)&outputText, plContext),
+ PKIX_MALLOCFAILED);
+
+ for (i = 0, j = 0; i < bigInt->length; i += 1, j += 2){
+ outputText[j] = pkix_i2hex
+ ((char) ((*(bigInt->dataRep+i) & 0xf0) >> 4));
+ outputText[j+1] = pkix_i2hex
+ ((char) (*(bigInt->dataRep+i) & 0x0f));
+ }
+
+ outputText[lengthChars-1] = '\0';
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII,
+ outputText,
+ 0,
+ pString,
+ plContext),
+ PKIX_STRINGCREATEFAILED);
+
+cleanup:
+
+ PKIX_FREE(outputText);
+
+ PKIX_RETURN(BIGINT);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_BigInt_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_BigInt_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_BigInt *bigInt = NULL;
+
+ PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_BIGINT_TYPE, plContext),
+ PKIX_OBJECTNOTBIGINT);
+
+ bigInt = (PKIX_PL_BigInt*)object;
+
+ PKIX_CHECK(pkix_hash
+ ((void *)bigInt->dataRep,
+ bigInt->length,
+ pHashcode,
+ plContext),
+ PKIX_HASHFAILED);
+
+cleanup:
+
+ PKIX_RETURN(BIGINT);
+}
+
+/*
+ * FUNCTION: pkix_pl_BigInt_Equals
+ * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_BigInt_Equals(
+ PKIX_PL_Object *first,
+ PKIX_PL_Object *second,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_UInt32 secondType;
+ PKIX_Int32 cmpResult = 0;
+
+ PKIX_ENTER(BIGINT, "pkix_pl_BigInt_Equals");
+ PKIX_NULLCHECK_THREE(first, second, pResult);
+
+ PKIX_CHECK(pkix_CheckType(first, PKIX_BIGINT_TYPE, plContext),
+ PKIX_FIRSTOBJECTNOTBIGINT);
+
+ PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+
+ *pResult = PKIX_FALSE;
+
+ if (secondType != PKIX_BIGINT_TYPE) goto cleanup;
+
+ PKIX_CHECK(pkix_pl_BigInt_Comparator
+ (first, second, &cmpResult, plContext),
+ PKIX_BIGINTCOMPARATORFAILED);
+
+ *pResult = (cmpResult == 0);
+
+cleanup:
+
+ PKIX_RETURN(BIGINT);
+}
+
+/*
+ * FUNCTION: pkix_pl_BigInt_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_BIGINT_TYPE and its related functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_BigInt_RegisterSelf(void *plContext)
+{
+
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(BIGINT, "pkix_pl_BigInt_RegisterSelf");
+
+ entry.description = "BigInt";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_BigInt);
+ entry.destructor = pkix_pl_BigInt_Destroy;
+ entry.equalsFunction = pkix_pl_BigInt_Equals;
+ entry.hashcodeFunction = pkix_pl_BigInt_Hashcode;
+ entry.toStringFunction = pkix_pl_BigInt_ToString;
+ entry.comparator = pkix_pl_BigInt_Comparator;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_BIGINT_TYPE] = entry;
+
+ PKIX_RETURN(BIGINT);
+}
+
+/*
+ * FUNCTION: pkix_pl_BigInt_CreateWithBytes
+ * DESCRIPTION:
+ *
+ * Creates a new BigInt of size "length" representing the array of bytes
+ * pointed to by "bytes" and stores it at "pBigInt". The caller should make
+ * sure that the first byte is not 0x00 (unless it is the the only byte).
+ * This function does not do that checking.
+ *
+ * Once created, a PKIX_PL_BigInt object is immutable.
+ *
+ * PARAMETERS:
+ * "bytes"
+ * Address of array of bytes. Must be non-NULL.
+ * "length"
+ * Length of the array. Must be non-zero.
+ * "pBigInt"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext" - Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_BigInt_CreateWithBytes(
+ char *bytes,
+ PKIX_UInt32 length,
+ PKIX_PL_BigInt **pBigInt,
+ void *plContext)
+{
+ PKIX_PL_BigInt *bigInt = NULL;
+
+ PKIX_ENTER(BIGINT, "pkix_pl_BigInt_CreateWithBytes");
+ PKIX_NULLCHECK_TWO(pBigInt, bytes);
+
+ if (length == 0) {
+ PKIX_ERROR(PKIX_BIGINTLENGTH0INVALID)
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_BIGINT_TYPE,
+ sizeof (PKIX_PL_BigInt),
+ (PKIX_PL_Object **)&bigInt,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ PKIX_CHECK(PKIX_PL_Malloc
+ (length, (void **)&(bigInt->dataRep), plContext),
+ PKIX_MALLOCFAILED);
+
+ PKIX_BIGINT_DEBUG("\t\tCalling PORT_Memcpy).\n");
+ (void) PORT_Memcpy(bigInt->dataRep, bytes, length);
+
+ bigInt->length = length;
+
+ *pBigInt = bigInt;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(bigInt);
+ }
+
+ PKIX_RETURN(BIGINT);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_BigInt_Create (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_BigInt_Create(
+ PKIX_PL_String *stringRep,
+ PKIX_PL_BigInt **pBigInt,
+ void *plContext)
+{
+ PKIX_PL_BigInt *bigInt = NULL;
+ char *asciiString = NULL;
+ PKIX_UInt32 lengthBytes;
+ PKIX_UInt32 lengthString;
+ PKIX_UInt32 i;
+ char currChar;
+
+ PKIX_ENTER(BIGINT, "PKIX_PL_BigInt_Create");
+ PKIX_NULLCHECK_TWO(pBigInt, stringRep);
+
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ (stringRep,
+ PKIX_ESCASCII,
+ (void **)&asciiString,
+ &lengthString,
+ plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+
+ if ((lengthString == 0) || ((lengthString % 2) != 0)){
+ PKIX_ERROR(PKIX_SOURCESTRINGHASINVALIDLENGTH);
+ }
+
+ if (lengthString != 2){
+ if ((asciiString[0] == '0') && (asciiString[1] == '0')){
+ PKIX_ERROR(PKIX_FIRSTDOUBLEHEXMUSTNOTBE00);
+ }
+ }
+
+ for (i = 0; i < lengthString; i++) {
+ currChar = asciiString[i];
+ if (!PKIX_ISXDIGIT(currChar)){
+ PKIX_ERROR(PKIX_INVALIDCHARACTERINBIGINT);
+ }
+ }
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_BIGINT_TYPE,
+ sizeof (PKIX_PL_BigInt),
+ (PKIX_PL_Object **)&bigInt,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+
+ /* number of bytes = 0.5 * (number of chars) */
+ lengthBytes = lengthString/2;
+
+ PKIX_CHECK(PKIX_PL_Malloc
+ (lengthBytes, (void **)&(bigInt->dataRep), plContext),
+ PKIX_MALLOCFAILED);
+
+ for (i = 0; i < lengthString; i += 2){
+ (bigInt->dataRep)[i/2] =
+ (pkix_hex2i(asciiString[i])<<4) |
+ pkix_hex2i(asciiString[i+1]);
+ }
+
+ bigInt->length = lengthBytes;
+
+ *pBigInt = bigInt;
+
+cleanup:
+
+ PKIX_FREE(asciiString);
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(bigInt);
+ }
+
+ PKIX_RETURN(BIGINT);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bigint.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bigint.h
new file mode 100755
index 000000000..b3df808a8
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bigint.h
@@ -0,0 +1,40 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_bigint.h
+ *
+ * Bigint Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_BIGINT_H
+#define _PKIX_PL_BIGINT_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_BigIntStruct {
+ char *dataRep;
+ PKIX_UInt32 length;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_pl_BigInt_CreateWithBytes(
+ char *bytes,
+ PKIX_UInt32 length,
+ PKIX_PL_BigInt **pBigInt,
+ void *plContext);
+
+PKIX_Error *pkix_pl_BigInt_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_BIGINT_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bytearray.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bytearray.c
new file mode 100755
index 000000000..0a2e9c08f
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bytearray.c
@@ -0,0 +1,504 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_bytearray.c
+ *
+ * ByteArray Object Functions
+ *
+ */
+
+#include "pkix_pl_bytearray.h"
+
+/* --Private-ByteArray-Functions------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_ByteArray_ToHexString
+ * DESCRIPTION:
+ *
+ * Creates a hex-String representation of the ByteArray pointed to by "array"
+ * and stores the result at "pString". The hex-String consists of hex-digit
+ * pairs separated by spaces, and the entire string enclosed within square
+ * brackets, e.g. [43 61 6E 20 79 6F 75 20 72 65 61 64 20 74 68 69 73 3F].
+ * A zero-length ByteArray is represented as [].
+ * PARAMETERS
+ * "array"
+ * ByteArray to be represented by the hex-String; must be non-NULL
+ * "pString"
+ * Address where String will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Cert Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_ByteArray_ToHexString(
+ PKIX_PL_ByteArray *array,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ char *tempText = NULL;
+ char *stringText = NULL; /* "[XX XX XX ...]" */
+ PKIX_UInt32 i, outputLen, bufferSize;
+
+ PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_ToHexString");
+ PKIX_NULLCHECK_TWO(array, pString);
+
+ if ((array->length) == 0) {
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, "[]", 0, pString, plContext),
+ PKIX_COULDNOTCREATESTRING);
+ } else {
+ /*
+ * Allocate space for format string
+ * '[' + "XX" + (n-1)*" XX" + ']' + '\0'
+ */
+ bufferSize = 2 + (3*(array->length));
+
+ PKIX_CHECK(PKIX_PL_Malloc
+ (bufferSize, (void **)&stringText, plContext),
+ PKIX_COULDNOTALLOCATEMEMORY);
+
+ stringText[0] = 0;
+ outputLen = 0;
+
+ PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf).\n");
+ tempText = PR_smprintf
+ ("[%02X", (0x0FF&((char *)(array->array))[0]));
+ PKIX_BYTEARRAY_DEBUG("\tCalling PL_strlen).\n");
+ outputLen += PL_strlen(tempText);
+
+ PKIX_BYTEARRAY_DEBUG("\tCalling PL_strcat).\n");
+ stringText = PL_strcat(stringText, tempText);
+
+ PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf_free).\n");
+ PR_smprintf_free(tempText);
+
+ for (i = 1; i < array->length; i++) {
+ PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf).\n");
+ tempText = PR_smprintf
+ (" %02X", (0x0FF&((char *)(array->array))[i]));
+
+ if (tempText == NULL){
+ PKIX_ERROR(PKIX_PRSMPRINTFFAILED);
+ }
+
+ PKIX_BYTEARRAY_DEBUG("\tCalling PL_strlen).\n");
+ outputLen += PL_strlen(tempText);
+
+ PKIX_BYTEARRAY_DEBUG("\tCalling PL_strcat).\n");
+ stringText = PL_strcat(stringText, tempText);
+
+ PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf_free).\n");
+ PR_smprintf_free(tempText);
+ tempText = NULL;
+ }
+
+ stringText[outputLen++] = ']';
+ stringText[outputLen] = 0;
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII,
+ stringText,
+ 0,
+ pString,
+ plContext),
+ PKIX_COULDNOTCREATESTRING);
+ }
+
+cleanup:
+
+ PKIX_FREE(stringText);
+ PKIX_RETURN(BYTEARRAY);
+}
+
+/*
+ * FUNCTION: pkix_pl_ByteArray_Comparator
+ * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h)
+ *
+ * NOTE:
+ * It is not clear that this definition of comparing byte arrays makes
+ * sense. It does allow you to tell whether two blocks of memory are
+ * identical, so we only use it for the Equals function (i.e. we don't
+ * register it as a Compare function for ByteArray).
+ */
+static PKIX_Error *
+pkix_pl_ByteArray_Comparator(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Int32 *pResult,
+ void *plContext)
+{
+ PKIX_PL_ByteArray *firstByteArray = NULL;
+ PKIX_PL_ByteArray *secondByteArray = NULL;
+ unsigned char *firstData = NULL;
+ unsigned char *secondData = NULL;
+ PKIX_UInt32 i;
+
+ PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_Comparator");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ PKIX_CHECK(pkix_CheckTypes
+ (firstObject, secondObject, PKIX_BYTEARRAY_TYPE, plContext),
+ PKIX_ARGUMENTSNOTBYTEARRAYS);
+
+ /* It's safe to cast */
+ firstByteArray = (PKIX_PL_ByteArray *)firstObject;
+ secondByteArray = (PKIX_PL_ByteArray *)secondObject;
+
+ *pResult = 0;
+ firstData = (unsigned char *)firstByteArray->array;
+ secondData = (unsigned char *)secondByteArray->array;
+
+ if (firstByteArray->length < secondByteArray->length) {
+ *pResult = -1;
+ } else if (firstByteArray->length > secondByteArray->length) {
+ *pResult = 1;
+ } else if (firstByteArray->length == secondByteArray->length) {
+ /* Check if both array contents are identical */
+ for (i = 0;
+ (i < firstByteArray->length) && (*pResult == 0);
+ i++) {
+ if (firstData[i] < secondData[i]) {
+ *pResult = -1;
+ } else if (firstData[i] > secondData[i]) {
+ *pResult = 1;
+ }
+ }
+ }
+
+cleanup:
+
+ PKIX_RETURN(BYTEARRAY);
+}
+
+/*
+ * FUNCTION: pkix_pl_ByteArray_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_ByteArray_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_ByteArray *array = NULL;
+ char *tempText = NULL;
+ char *stringText = NULL; /* "[OOO, OOO, ... OOO]" */
+ PKIX_UInt32 i, outputLen, bufferSize;
+
+ PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_ToString");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_BYTEARRAY_TYPE, plContext),
+ PKIX_OBJECTNOTBYTEARRAY);
+
+ array = (PKIX_PL_ByteArray *)object;
+
+ if ((array->length) == 0) {
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, "[]", 0, pString, plContext),
+ PKIX_COULDNOTCREATESTRING);
+ } else {
+ /* Allocate space for "XXX, ". */
+ bufferSize = 2+5*array->length;
+
+ /* Allocate space for format string */
+ PKIX_CHECK(PKIX_PL_Malloc
+ (bufferSize, (void **)&stringText, plContext),
+ PKIX_MALLOCFAILED);
+
+ stringText[0] = 0;
+ outputLen = 0;
+
+ PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf).\n");
+ tempText =
+ PR_smprintf
+ ("[%03u", (0x0FF&((char *)(array->array))[0]));
+ PKIX_BYTEARRAY_DEBUG("\tCalling PL_strlen).\n");
+ outputLen += PL_strlen(tempText);
+
+ PKIX_BYTEARRAY_DEBUG("\tCalling PL_strcat).\n");
+ stringText = PL_strcat(stringText, tempText);
+
+ PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf_free).\n");
+ PR_smprintf_free(tempText);
+
+ for (i = 1; i < array->length; i++) {
+ PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf).\n");
+ tempText = PR_smprintf
+ (", %03u",
+ (0x0FF&((char *)(array->array))[i]));
+
+ if (tempText == NULL){
+ PKIX_ERROR(PKIX_PRSMPRINTFFAILED);
+ }
+
+ PKIX_BYTEARRAY_DEBUG("\tCalling PL_strlen).\n");
+ outputLen += PL_strlen(tempText);
+
+ PKIX_BYTEARRAY_DEBUG("\tCalling PL_strcat).\n");
+ stringText = PL_strcat(stringText, tempText);
+
+ PKIX_BYTEARRAY_DEBUG("\tCalling PR_smprintf_free).\n");
+ PR_smprintf_free(tempText);
+ tempText = NULL;
+ }
+
+ stringText[outputLen++] = ']';
+ stringText[outputLen] = 0;
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, stringText, 0, pString, plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ }
+
+cleanup:
+
+ PKIX_FREE(stringText);
+ PKIX_RETURN(BYTEARRAY);
+}
+
+/*
+ * FUNCTION: pkix_pl_ByteArray_Equals
+ * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_ByteArray_Equals(
+ PKIX_PL_Object *first,
+ PKIX_PL_Object *second,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_UInt32 secondType;
+ PKIX_Int32 cmpResult = 0;
+
+ PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_Equals");
+ PKIX_NULLCHECK_THREE(first, second, pResult);
+
+ /* Sanity check: Test that "first" is a ByteArray */
+ PKIX_CHECK(pkix_CheckType(first, PKIX_BYTEARRAY_TYPE, plContext),
+ PKIX_FIRSTARGUMENTNOTBYTEARRAY);
+
+ PKIX_CHECK(PKIX_PL_Object_GetType(second, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+
+ /* If types differ, then we will return false */
+ *pResult = PKIX_FALSE;
+
+ /* Second type may not be a BA */
+ if (secondType != PKIX_BYTEARRAY_TYPE) goto cleanup;
+
+ /* It's safe to cast here */
+ PKIX_CHECK(pkix_pl_ByteArray_Comparator
+ (first, second, &cmpResult, plContext),
+ PKIX_BYTEARRAYCOMPARATORFAILED);
+
+ /* ByteArrays are equal iff Comparator Result is 0 */
+ *pResult = (cmpResult == 0);
+
+cleanup:
+
+ PKIX_RETURN(BYTEARRAY);
+}
+
+/*
+ * FUNCTION: pkix_pl_ByteArray_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_ByteArray_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_ByteArray *array = NULL;
+
+ PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_BYTEARRAY_TYPE, plContext),
+ PKIX_OBJECTNOTBYTEARRAY);
+
+ array = (PKIX_PL_ByteArray*)object;
+
+ PKIX_FREE(array->array);
+ array->array = NULL;
+ array->length = 0;
+
+cleanup:
+
+ PKIX_RETURN(BYTEARRAY);
+}
+
+/*
+ * FUNCTION: pkix_pl_ByteArray_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_ByteArray_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_ByteArray *array = NULL;
+
+ PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_BYTEARRAY_TYPE, plContext),
+ PKIX_OBJECTNOTBYTEARRAY);
+
+ array = (PKIX_PL_ByteArray*)object;
+
+ PKIX_CHECK(pkix_hash
+ ((const unsigned char *)array->array,
+ array->length,
+ pHashcode,
+ plContext),
+ PKIX_HASHFAILED);
+
+cleanup:
+
+ PKIX_RETURN(BYTEARRAY);
+}
+
+/*
+ * FUNCTION: pkix_pl_ByteArray_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_BYTEARRAY_TYPE and its related functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_ByteArray_RegisterSelf(void *plContext)
+{
+
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(BYTEARRAY, "pkix_pl_ByteArray_RegisterSelf");
+
+ entry.description = "ByteArray";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_ByteArray);
+ entry.destructor = pkix_pl_ByteArray_Destroy;
+ entry.equalsFunction = pkix_pl_ByteArray_Equals;
+ entry.hashcodeFunction = pkix_pl_ByteArray_Hashcode;
+ entry.toStringFunction = pkix_pl_ByteArray_ToString;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_BYTEARRAY_TYPE] = entry;
+
+ PKIX_RETURN(BYTEARRAY);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_ByteArray_Create (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_ByteArray_Create(
+ void *array,
+ PKIX_UInt32 length,
+ PKIX_PL_ByteArray **pByteArray,
+ void *plContext)
+{
+ PKIX_PL_ByteArray *byteArray = NULL;
+
+ PKIX_ENTER(BYTEARRAY, "PKIX_PL_ByteArray_Create");
+ PKIX_NULLCHECK_ONE(pByteArray);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_BYTEARRAY_TYPE,
+ sizeof (PKIX_PL_ByteArray),
+ (PKIX_PL_Object **)&byteArray,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECTSTORAGE);
+
+ byteArray->length = length;
+ byteArray->array = NULL;
+
+ if (length != 0){
+ /* Alloc space for array */
+ PKIX_NULLCHECK_ONE(array);
+
+ PKIX_CHECK(PKIX_PL_Malloc
+ (length, (void**)&(byteArray->array), plContext),
+ PKIX_MALLOCFAILED);
+
+ PKIX_BYTEARRAY_DEBUG("\tCalling PORT_Memcpy).\n");
+ (void) PORT_Memcpy(byteArray->array, array, length);
+ }
+
+ *pByteArray = byteArray;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(byteArray);
+ }
+
+ PKIX_RETURN(BYTEARRAY);
+}
+
+/*
+ * FUNCTION: PKIX_PL_ByteArray_GetPointer (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_ByteArray_GetPointer(
+ PKIX_PL_ByteArray *byteArray,
+ void **pArray,
+ void *plContext)
+{
+ void *bytes = NULL;
+ PKIX_ENTER(BYTEARRAY, "PKIX_PL_ByteArray_GetPointer");
+ PKIX_NULLCHECK_TWO(byteArray, pArray);
+
+ if (byteArray->length != 0){
+ PKIX_CHECK(PKIX_PL_Malloc
+ (byteArray->length, &bytes, plContext),
+ PKIX_MALLOCFAILED);
+
+ PKIX_BYTEARRAY_DEBUG("\tCalling PORT_Memcpy).\n");
+ (void) PORT_Memcpy
+ (bytes, byteArray->array, byteArray->length);
+ }
+
+ *pArray = bytes;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_FREE(bytes);
+ }
+
+ PKIX_RETURN(BYTEARRAY);
+}
+
+/*
+ * FUNCTION: PKIX_PL_ByteArray_GetLength (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_ByteArray_GetLength(
+ PKIX_PL_ByteArray *byteArray,
+ PKIX_UInt32 *pLength,
+ void *plContext)
+{
+ PKIX_ENTER(BYTEARRAY, "PKIX_PL_ByteArray_GetLength");
+ PKIX_NULLCHECK_TWO(byteArray, pLength);
+
+ *pLength = byteArray->length;
+
+ PKIX_RETURN(BYTEARRAY);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bytearray.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bytearray.h
new file mode 100755
index 000000000..4ba18eed7
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_bytearray.h
@@ -0,0 +1,40 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_bytearray.h
+ *
+ * ByteArray Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_BYTEARRAY_H
+#define _PKIX_PL_BYTEARRAY_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_ByteArrayStruct {
+ void *array;
+ PKIX_UInt32 length;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_pl_ByteArray_ToHexString(
+ PKIX_PL_ByteArray *array,
+ PKIX_PL_String **pString,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_ByteArray_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_BYTEARRAY_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_common.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_common.c
new file mode 100755
index 000000000..831ce538d
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_common.c
@@ -0,0 +1,1073 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_common.c
+ *
+ * Common utility functions used by various PKIX_PL functions
+ *
+ */
+
+#include "pkix_pl_common.h"
+
+/* --Private-Functions-------------------------------------------- */
+
+/*
+ * FUNCTION: pkix_LockObject
+ * DESCRIPTION:
+ *
+ * Locks the object pointed to by "object".
+ *
+ * PARAMETERS:
+ * "object"
+ * Address of object. Must be non-NULL
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_LockObject(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_Object *objectHeader;
+
+ PKIX_ENTER(OBJECT, "pkix_LockObject");
+ PKIX_NULLCHECK_ONE(object);
+
+ if (object == (PKIX_PL_Object *)PKIX_ALLOC_ERROR()) {
+ goto cleanup;
+ }
+
+ PKIX_OBJECT_DEBUG("\tShifting object pointer).\n");
+ /* The header is sizeof(PKIX_PL_Object) before the object pointer */
+
+ objectHeader = object-1;
+
+ PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
+ PR_Lock(objectHeader->lock);
+
+cleanup:
+
+ PKIX_RETURN(OBJECT);
+}
+
+/*
+ * FUNCTION: pkix_UnlockObject
+ * DESCRIPTION:
+ *
+ * Unlocks the object pointed to by "object".
+ *
+ * PARAMETERS:
+ * "object"
+ * Address of Object. Must be non-NULL
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_UnlockObject(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_Object *objectHeader;
+ PRStatus result;
+
+ PKIX_ENTER(OBJECT, "pkix_UnlockObject");
+ PKIX_NULLCHECK_ONE(object);
+
+ if (object == (PKIX_PL_Object *)PKIX_ALLOC_ERROR()) {
+ goto cleanup;
+ }
+
+ PKIX_OBJECT_DEBUG("\tShifting object pointer).\n");
+ /* The header is sizeof(PKIX_PL_Object) before the object pointer */
+
+ objectHeader = object-1;
+
+ PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
+ result = PR_Unlock(objectHeader->lock);
+
+ if (result == PR_FAILURE) {
+ PKIX_OBJECT_DEBUG("\tPR_Unlock failed.).\n");
+ PKIX_ERROR_FATAL(PKIX_ERRORUNLOCKINGOBJECT);
+ }
+
+cleanup:
+
+ PKIX_RETURN(OBJECT);
+}
+
+/*
+ * FUNCTION: pkix_pl_UInt32_Overflows
+ * DESCRIPTION:
+ *
+ * Returns a PKIX_Boolean indicating whether the unsigned integer
+ * represented by "string" is too large to fit in 32-bits (i.e.
+ * whether it overflows). With the exception of the string "0",
+ * all other strings are stripped of any leading zeros. It is assumed
+ * that every character in "string" is from the set {'0' - '9'}.
+ *
+ * PARAMETERS
+ * "string"
+ * Address of array of bytes representing PKIX_UInt32 that's being tested
+ * for 32-bit overflow
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * PKIX_TRUE if PKIX_UInt32 represented by "string" overflows;
+ * PKIX_FALSE otherwise
+ */
+PKIX_Boolean
+pkix_pl_UInt32_Overflows(char *string){
+ char *firstNonZero = NULL;
+ PKIX_UInt32 length, i;
+ char *MAX_UINT32_STRING = "4294967295";
+
+ PKIX_DEBUG_ENTER(OID);
+
+ PKIX_OID_DEBUG("\tCalling PL_strlen).\n");
+ length = PL_strlen(string);
+
+ if (length < MAX_DIGITS_32){
+ return (PKIX_FALSE);
+ }
+
+ firstNonZero = string;
+ for (i = 0; i < length; i++){
+ if (*string == '0'){
+ firstNonZero++;
+ }
+ }
+
+ PKIX_OID_DEBUG("\tCalling PL_strlen).\n");
+ length = PL_strlen(firstNonZero);
+
+ if (length > MAX_DIGITS_32){
+ return (PKIX_TRUE);
+ }
+
+ PKIX_OID_DEBUG("\tCalling PL_strlen).\n");
+ if (length == MAX_DIGITS_32){
+ PKIX_OID_DEBUG("\tCalling PORT_Strcmp).\n");
+ if (PORT_Strcmp(firstNonZero, MAX_UINT32_STRING) > 0){
+ return (PKIX_TRUE);
+ }
+ }
+
+ return (PKIX_FALSE);
+}
+
+/*
+ * FUNCTION: pkix_pl_getOIDToken
+ * DESCRIPTION:
+ *
+ * Takes the array of DER-encoded bytes pointed to by "derBytes"
+ * (representing an OID) and the value of "index" representing the index into
+ * the array, and decodes the bytes until an integer token is retrieved. If
+ * successful, this function stores the integer component at "pToken" and
+ * stores the index representing the next byte in the array at "pIndex"
+ * (following the last byte that was used in the decoding). This new output
+ * index can be used in subsequent calls as an input index, allowing each
+ * token of the OID to be retrieved consecutively. Note that there is a
+ * special case for the first byte, in that it encodes two separate integer
+ * tokens. For example, the byte {2a} represents the integer tokens {1,2}.
+ * This special case is not handled here and must be handled by the caller.
+ *
+ * PARAMETERS
+ * "derBytes"
+ * Address of array of bytes representing a DER-encoded OID.
+ * Must be non-NULL.
+ * "index"
+ * Index into the array that this function will begin decoding at.
+ * "pToken"
+ * Destination for decoded OID token. Must be non-NULL.
+ * "pIndex"
+ * Destination for index of next byte following last byte used.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an Object Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_getOIDToken(
+ char *derBytes,
+ PKIX_UInt32 index,
+ PKIX_UInt32 *pToken,
+ PKIX_UInt32 *pIndex,
+ void *plContext)
+{
+ PKIX_UInt32 retval, i, tmp;
+
+ PKIX_ENTER(OID, "pkix_pl_getOIDToken");
+ PKIX_NULLCHECK_THREE(derBytes, pToken, pIndex);
+
+ /*
+ * We should only need to parse a maximum of four bytes, because
+ * RFC 3280 "mandates support for OIDs which have arc elements
+ * with values that are less than 2^28, that is, they MUST be between
+ * 0 and 268,435,455, inclusive. This allows each arc element to be
+ * represented within a single 32 bit word."
+ */
+
+ for (i = 0, retval = 0; i < 4; i++) {
+ retval <<= 7;
+ tmp = derBytes[index];
+ index++;
+ retval |= (tmp & 0x07f);
+ if ((tmp & 0x080) == 0){
+ *pToken = retval;
+ *pIndex = index;
+ goto cleanup;
+ }
+ }
+
+ PKIX_ERROR(PKIX_INVALIDENCODINGOIDTOKENVALUETOOBIG);
+
+cleanup:
+
+ PKIX_RETURN(OID);
+
+}
+
+/*
+ * FUNCTION: pkix_pl_helperBytes2Ascii
+ * DESCRIPTION:
+ *
+ * Converts an array of integers pointed to by "tokens" with a length of
+ * "numTokens", to an ASCII string consisting of those integers with dots in
+ * between them and stores the result at "pAscii". The ASCII representation is
+ * guaranteed to end with a NUL character. This is particularly useful for
+ * OID's and IP Addresses.
+ *
+ * The return value "pAscii" is not reference-counted and will need to
+ * be freed with PKIX_PL_Free.
+ *
+ * PARAMETERS
+ * "tokens"
+ * Address of array of integers. Must be non-NULL.
+ * "numTokens"
+ * Length of array of integers. Must be non-zero.
+ * "pAscii"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an Object Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_helperBytes2Ascii(
+ PKIX_UInt32 *tokens,
+ PKIX_UInt32 numTokens,
+ char **pAscii,
+ void *plContext)
+{
+ char *tempString = NULL;
+ char *outputString = NULL;
+ char *format = "%d";
+ PKIX_UInt32 i = 0;
+ PKIX_UInt32 outputLen = 0;
+ PKIX_Int32 error;
+
+ PKIX_ENTER(OBJECT, "pkix_pl_helperBytes2Ascii");
+ PKIX_NULLCHECK_TWO(tokens, pAscii);
+
+ if (numTokens == 0) {
+ PKIX_ERROR_FATAL(PKIX_HELPERBYTES2ASCIINUMTOKENSZERO);
+ }
+
+ /*
+ * tempString will hold the string representation of a PKIX_UInt32 type
+ * The maximum value that can be held by an unsigned 32-bit integer
+ * is (2^32 - 1) = 4294967295 (which is ten digits long)
+ * Since tempString will hold the string representation of a
+ * PKIX_UInt32, we allocate 11 bytes for it (1 byte for '\0')
+ */
+
+ PKIX_CHECK(PKIX_PL_Malloc
+ (MAX_DIGITS_32 + 1, (void **)&tempString, plContext),
+ PKIX_MALLOCFAILED);
+
+ for (i = 0; i < numTokens; i++){
+ PKIX_OBJECT_DEBUG("\tCalling PR_snprintf).\n");
+ error = PR_snprintf(tempString,
+ MAX_DIGITS_32 + 1,
+ format,
+ tokens[i]);
+ if (error == -1){
+ PKIX_ERROR(PKIX_PRSNPRINTFFAILED);
+ }
+
+ PKIX_OBJECT_DEBUG("\tCalling PL_strlen).\n");
+ outputLen += PL_strlen(tempString);
+
+ /* Include a dot to separate each number */
+ outputLen++;
+ }
+
+ /* Allocate space for the destination string */
+ PKIX_CHECK(PKIX_PL_Malloc
+ (outputLen, (void **)&outputString, plContext),
+ PKIX_MALLOCFAILED);
+
+ *outputString = '\0';
+
+ /* Concatenate all strings together */
+ for (i = 0; i < numTokens; i++){
+
+ PKIX_OBJECT_DEBUG("\tCalling PR_snprintf).\n");
+ error = PR_snprintf(tempString,
+ MAX_DIGITS_32 + 1,
+ format,
+ tokens[i]);
+ if (error == -1){
+ PKIX_ERROR(PKIX_PRSNPRINTFFAILED);
+ }
+
+ PKIX_OBJECT_DEBUG("\tCalling PL_strcat).\n");
+ (void) PL_strcat(outputString, tempString);
+
+ /* we don't want to put a "." at the very end */
+ if (i < (numTokens - 1)){
+ PKIX_OBJECT_DEBUG("\tCalling PL_strcat).\n");
+ (void) PL_strcat(outputString, ".");
+ }
+ }
+
+ /* Ensure output string ends with terminating null */
+ outputString[outputLen-1] = '\0';
+
+ *pAscii = outputString;
+ outputString = NULL;
+
+cleanup:
+
+ PKIX_FREE(outputString);
+ PKIX_FREE(tempString);
+
+ PKIX_RETURN(OBJECT);
+
+}
+
+/*
+ * FUNCTION: pkix_pl_ipAddrBytes2Ascii
+ * DESCRIPTION:
+ *
+ * Converts the DER encoding of an IPAddress pointed to by "secItem" to an
+ * ASCII representation and stores the result at "pAscii". The ASCII
+ * representation is guaranteed to end with a NUL character. The input
+ * SECItem must contain non-NULL data and must have a positive length.
+ *
+ * The return value "pAscii" is not reference-counted and will need to
+ * be freed with PKIX_PL_Free.
+ * XXX this function assumes that IPv4 addresses are being used
+ * XXX what about IPv6? can NSS tell the difference
+ *
+ * PARAMETERS
+ * "secItem"
+ * Address of SECItem which contains bytes and length of DER encoding.
+ * Must be non-NULL.
+ * "pAscii"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an Object Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_ipAddrBytes2Ascii(
+ SECItem *secItem,
+ char **pAscii,
+ void *plContext)
+{
+ char *data = NULL;
+ PKIX_UInt32 *tokens = NULL;
+ PKIX_UInt32 numTokens = 0;
+ PKIX_UInt32 i = 0;
+ char *asciiString = NULL;
+
+ PKIX_ENTER(OBJECT, "pkix_pl_ipAddrBytes2Ascii");
+ PKIX_NULLCHECK_THREE(secItem, pAscii, secItem->data);
+
+ if (secItem->len == 0) {
+ PKIX_ERROR_FATAL(PKIX_IPADDRBYTES2ASCIIDATALENGTHZERO);
+ }
+
+ data = (char *)(secItem->data);
+ numTokens = secItem->len;
+
+ /* allocate space for array of integers */
+ PKIX_CHECK(PKIX_PL_Malloc
+ (numTokens * sizeof (PKIX_UInt32),
+ (void **)&tokens,
+ plContext),
+ PKIX_MALLOCFAILED);
+
+ /* populate array of integers */
+ for (i = 0; i < numTokens; i++){
+ tokens[i] = data[i];
+ }
+
+ /* convert array of integers to ASCII */
+ PKIX_CHECK(pkix_pl_helperBytes2Ascii
+ (tokens, numTokens, &asciiString, plContext),
+ PKIX_HELPERBYTES2ASCIIFAILED);
+
+ *pAscii = asciiString;
+
+cleanup:
+
+ PKIX_FREE(tokens);
+
+ PKIX_RETURN(OBJECT);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_oidBytes2Ascii
+ * DESCRIPTION:
+ *
+ * Converts the DER encoding of an OID pointed to by "secItem" to an ASCII
+ * representation and stores it at "pAscii". The ASCII representation is
+ * guaranteed to end with a NUL character. The input SECItem must contain
+ * non-NULL data and must have a positive length.
+ *
+ * Example: the six bytes {2a 86 48 86 f7 0d} represent the
+ * four integer tokens {1, 2, 840, 113549}, which we will convert
+ * into ASCII yielding "1.2.840.113549"
+ *
+ * The return value "pAscii" is not reference-counted and will need to
+ * be freed with PKIX_PL_Free.
+ *
+ * PARAMETERS
+ * "secItem"
+ * Address of SECItem which contains bytes and length of DER encoding.
+ * Must be non-NULL.
+ * "pAscii"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an OID Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_oidBytes2Ascii(
+ SECItem *secItem,
+ char **pAscii,
+ void *plContext)
+{
+ char *data = NULL;
+ PKIX_UInt32 *tokens = NULL;
+ PKIX_UInt32 token = 0;
+ PKIX_UInt32 numBytes = 0;
+ PKIX_UInt32 numTokens = 0;
+ PKIX_UInt32 i = 0, x = 0, y = 0;
+ PKIX_UInt32 index = 0;
+ char *asciiString = NULL;
+
+ PKIX_ENTER(OID, "pkix_pl_oidBytes2Ascii");
+ PKIX_NULLCHECK_THREE(secItem, pAscii, secItem->data);
+
+ if (secItem->len == 0) {
+ PKIX_ERROR_FATAL(PKIX_OIDBYTES2ASCIIDATALENGTHZERO);
+ }
+
+ data = (char *)(secItem->data);
+ numBytes = secItem->len;
+ numTokens = 0;
+
+ /* calculate how many integer tokens are represented by the bytes. */
+ for (i = 0; i < numBytes; i++){
+ if ((data[i] & 0x080) == 0){
+ numTokens++;
+ }
+ }
+
+ /* if we are unable to retrieve any tokens at all, we throw an error */
+ if (numTokens == 0){
+ PKIX_ERROR(PKIX_INVALIDDERENCODINGFOROID);
+ }
+
+ /* add one more token b/c the first byte always contains two tokens */
+ numTokens++;
+
+ /* allocate space for array of integers */
+ PKIX_CHECK(PKIX_PL_Malloc
+ (numTokens * sizeof (PKIX_UInt32),
+ (void **)&tokens,
+ plContext),
+ PKIX_MALLOCFAILED);
+
+ /* populate array of integers */
+ for (i = 0; i < numTokens; i++){
+
+ /* retrieve integer token */
+ PKIX_CHECK(pkix_pl_getOIDToken
+ (data, index, &token, &index, plContext),
+ PKIX_GETOIDTOKENFAILED);
+
+ if (i == 0){
+
+ /*
+ * special case: the first DER-encoded byte represents
+ * two tokens. We take advantage of fact that first
+ * token must be 0, 1, or 2; and second token must be
+ * between {0, 39} inclusive if first token is 0 or 1.
+ */
+
+ if (token < 40)
+ x = 0;
+ else if (token < 80)
+ x = 1;
+ else
+ x = 2;
+ y = token - (x * 40);
+
+ tokens[0] = x;
+ tokens[1] = y;
+ i++;
+ } else {
+ tokens[i] = token;
+ }
+ }
+
+ /* convert array of integers to ASCII */
+ PKIX_CHECK(pkix_pl_helperBytes2Ascii
+ (tokens, numTokens, &asciiString, plContext),
+ PKIX_HELPERBYTES2ASCIIFAILED);
+
+ *pAscii = asciiString;
+
+cleanup:
+
+ PKIX_FREE(tokens);
+ PKIX_RETURN(OID);
+
+}
+
+/*
+ * FUNCTION: pkix_UTF16_to_EscASCII
+ * DESCRIPTION:
+ *
+ * Converts array of bytes pointed to by "utf16String" with length of
+ * "utf16Length" (which must be even) into a freshly allocated Escaped ASCII
+ * string and stores a pointer to that string at "pDest" and stores the
+ * string's length at "pLength". The Escaped ASCII string's length does not
+ * include the final NUL character. The caller is responsible for freeing
+ * "pDest" using PKIX_PL_Free. If "debug" is set, uses EscASCII_Debug
+ * encoding.
+ *
+ * PARAMETERS:
+ * "utf16String"
+ * Address of array of bytes representing data source. Must be non-NULL.
+ * "utf16Length"
+ * Length of data source. Must be even.
+ * "debug"
+ * Boolean value indicating whether debug mode is desired.
+ * "pDest"
+ * Address where data will be stored. Must be non-NULL.
+ * "pLength"
+ * Address where data length will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a String Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_UTF16_to_EscASCII(
+ const void *utf16String,
+ PKIX_UInt32 utf16Length,
+ PKIX_Boolean debug,
+ char **pDest,
+ PKIX_UInt32 *pLength,
+ void *plContext)
+{
+ char *destPtr = NULL;
+ PKIX_UInt32 i, charLen;
+ PKIX_UInt32 x = 0, y = 0, z = 0;
+ unsigned char *utf16Char = (unsigned char *)utf16String;
+
+ PKIX_ENTER(STRING, "pkix_UTF16_to_EscASCII");
+ PKIX_NULLCHECK_THREE(utf16String, pDest, pLength);
+
+ /* Assume every pair of bytes becomes &#xNNNN; */
+ charLen = 4*utf16Length;
+
+ /* utf16Lenght must be even */
+ if ((utf16Length % 2) != 0){
+ PKIX_ERROR(PKIX_UTF16ALIGNMENTERROR);
+ }
+
+ /* Count how many bytes we need */
+ for (i = 0; i < utf16Length; i += 2) {
+ if ((utf16Char[i] == 0x00)&&
+ pkix_isPlaintext(utf16Char[i+1], debug)) {
+ if (utf16Char[i+1] == '&') {
+ /* Need to convert this to &amp; */
+ charLen -= 3;
+ } else {
+ /* We can fit this into one char */
+ charLen -= 7;
+ }
+ } else if ((utf16Char[i] >= 0xD8) && (utf16Char[i] <= 0xDB)) {
+ if ((i+3) >= utf16Length) {
+ PKIX_ERROR(PKIX_UTF16HIGHZONEALIGNMENTERROR);
+ } else if ((utf16Char[i+2] >= 0xDC)&&
+ (utf16Char[i+2] <= 0xDF)) {
+ /* Quartet of bytes will become &#xNNNNNNNN; */
+ charLen -= 4;
+ /* Quartet of bytes will produce 12 chars */
+ i += 2;
+ } else {
+ /* Second pair should be DC00-DFFF */
+ PKIX_ERROR(PKIX_UTF16LOWZONEERROR);
+ }
+ }
+ }
+
+ *pLength = charLen;
+
+ /* Ensure this string is null terminated */
+ charLen++;
+
+ /* Allocate space for character array */
+ PKIX_CHECK(PKIX_PL_Malloc(charLen, (void **)pDest, plContext),
+ PKIX_MALLOCFAILED);
+
+ destPtr = *pDest;
+ for (i = 0; i < utf16Length; i += 2) {
+ if ((utf16Char[i] == 0x00)&&
+ pkix_isPlaintext(utf16Char[i+1], debug)) {
+ /* Write a single character */
+ *destPtr++ = utf16Char[i+1];
+ } else if ((utf16Char[i+1] == '&') && (utf16Char[i] == 0x00)){
+ *destPtr++ = '&';
+ *destPtr++ = 'a';
+ *destPtr++ = 'm';
+ *destPtr++ = 'p';
+ *destPtr++ = ';';
+ } else if ((utf16Char[i] >= 0xD8)&&
+ (utf16Char[i] <= 0xDB)&&
+ (utf16Char[i+2] >= 0xDC)&&
+ (utf16Char[i+2] <= 0xDF)) {
+ /*
+ * Special UTF pairs are of the form:
+ * x = D800..DBFF; y = DC00..DFFF;
+ * The result is of the form:
+ * ((x - D800) * 400 + (y - DC00)) + 0001 0000
+ */
+ x = 0x0FFFF & ((utf16Char[i]<<8) | utf16Char[i+1]);
+ y = 0x0FFFF & ((utf16Char[i+2]<<8) | utf16Char[i+3]);
+ z = ((x - 0xD800) * 0x400 + (y - 0xDC00)) + 0x00010000;
+
+ /* Sprintf &#xNNNNNNNN; */
+ PKIX_STRING_DEBUG("\tCalling PR_snprintf).\n");
+ if (PR_snprintf(destPtr, 13, "&#x%08X;", z) ==
+ (PKIX_UInt32)(-1)) {
+ PKIX_ERROR(PKIX_PRSNPRINTFFAILED);
+ }
+ i += 2;
+ destPtr += 12;
+ } else {
+ /* Sprintf &#xNNNN; */
+ PKIX_STRING_DEBUG("\tCalling PR_snprintf).\n");
+ if (PR_snprintf
+ (destPtr,
+ 9,
+ "&#x%02X%02X;",
+ utf16Char[i],
+ utf16Char[i+1]) ==
+ (PKIX_UInt32)(-1)) {
+ PKIX_ERROR(PKIX_PRSNPRINTFFAILED);
+ }
+ destPtr += 8;
+ }
+ }
+ *destPtr = '\0';
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_FREE(*pDest);
+ }
+
+ PKIX_RETURN(STRING);
+}
+
+/*
+ * FUNCTION: pkix_EscASCII_to_UTF16
+ * DESCRIPTION:
+ *
+ * Converts array of bytes pointed to by "escAsciiString" with length of
+ * "escAsciiLength" into a freshly allocated UTF-16 string and stores a
+ * pointer to that string at "pDest" and stores the string's length at
+ * "pLength". The caller is responsible for freeing "pDest" using
+ * PKIX_PL_Free. If "debug" is set, uses EscASCII_Debug encoding.
+ *
+ * PARAMETERS:
+ * "escAsciiString"
+ * Address of array of bytes representing data source. Must be non-NULL.
+ * "escAsciiLength"
+ * Length of data source. Must be even.
+ * "debug"
+ * Boolean value indicating whether debug mode is desired.
+ * "pDest"
+ * Address where data will be stored. Must be non-NULL.
+ * "pLength"
+ * Address where data length will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a String Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_EscASCII_to_UTF16(
+ const char *escAsciiString,
+ PKIX_UInt32 escAsciiLen,
+ PKIX_Boolean debug,
+ void **pDest,
+ PKIX_UInt32 *pLength,
+ void *plContext)
+{
+ PKIX_UInt32 newLen, i, j, charSize;
+ PKIX_UInt32 x = 0, y = 0, z = 0;
+ unsigned char *destPtr = NULL;
+ unsigned char testChar, testChar2;
+ unsigned char *stringData = (unsigned char *)escAsciiString;
+
+ PKIX_ENTER(STRING, "pkix_EscASCII_to_UTF16");
+ PKIX_NULLCHECK_THREE(escAsciiString, pDest, pLength);
+
+ if (escAsciiLen == 0) {
+ PKIX_CHECK(PKIX_PL_Malloc(escAsciiLen, pDest, plContext),
+ PKIX_MALLOCFAILED);
+ goto cleanup;
+ }
+
+ /* Assume each unicode character takes two bytes */
+ newLen = escAsciiLen*2;
+
+ /* Count up number of unicode encoded characters */
+ for (i = 0; i < escAsciiLen; i++) {
+ if (!pkix_isPlaintext(stringData[i], debug)&&
+ (stringData[i] != '&')) {
+ PKIX_ERROR(PKIX_ILLEGALCHARACTERINESCAPEDASCII);
+ } else if (PL_strstr(escAsciiString+i, "&amp;") ==
+ escAsciiString+i) {
+ /* Convert EscAscii "&amp;" to two bytes */
+ newLen -= 8;
+ i += 4;
+ } else if ((PL_strstr(escAsciiString+i, "&#x") ==
+ escAsciiString+i)||
+ (PL_strstr(escAsciiString+i, "&#X") ==
+ escAsciiString+i)) {
+ if (((i+7) <= escAsciiLen)&&
+ (escAsciiString[i+7] == ';')) {
+ /* Convert &#xNNNN; to two bytes */
+ newLen -= 14;
+ i += 7;
+ } else if (((i+11) <= escAsciiLen)&&
+ (escAsciiString[i+11] == ';')) {
+ /* Convert &#xNNNNNNNN; to four bytes */
+ newLen -= 20;
+ i += 11;
+ } else {
+ PKIX_ERROR(PKIX_ILLEGALUSEOFAMP);
+ }
+ }
+ }
+
+ PKIX_CHECK(PKIX_PL_Malloc(newLen, pDest, plContext),
+ PKIX_MALLOCFAILED);
+
+ /* Copy into newly allocated space */
+ destPtr = (unsigned char *)*pDest;
+
+ i = 0;
+ while (i < escAsciiLen) {
+ /* Copy each byte until you hit a &amp; */
+ if (pkix_isPlaintext(escAsciiString[i], debug)) {
+ *destPtr++ = 0x00;
+ *destPtr++ = escAsciiString[i++];
+ } else if (PL_strstr(escAsciiString+i, "&amp;") ==
+ escAsciiString+i) {
+ /* Convert EscAscii "&amp;" to two bytes */
+ *destPtr++ = 0x00;
+ *destPtr++ = '&';
+ i += 5;
+ } else if (((PL_strstr(escAsciiString+i, "&#x") ==
+ escAsciiString+i)||
+ (PL_strstr(escAsciiString+i, "&#X") ==
+ escAsciiString+i))&&
+ ((i+7) <= escAsciiLen)) {
+
+ /* We're either looking at &#xNNNN; or &#xNNNNNNNN; */
+ charSize = (escAsciiString[i+7] == ';')?4:8;
+
+ /* Skip past the &#x */
+ i += 3;
+
+ /* Make sure there is a terminating semi-colon */
+ if (((i+charSize) > escAsciiLen)||
+ (escAsciiString[i+charSize] != ';')) {
+ PKIX_ERROR(PKIX_TRUNCATEDUNICODEINESCAPEDASCII);
+ }
+
+ for (j = 0; j < charSize; j++) {
+ if (!PKIX_ISXDIGIT
+ (escAsciiString[i+j])) {
+ PKIX_ERROR(PKIX_ILLEGALUNICODECHARACTER);
+ } else if (charSize == 8) {
+ x |= (pkix_hex2i
+ (escAsciiString[i+j]))
+ <<(4*(7-j));
+ }
+ }
+
+ testChar =
+ (pkix_hex2i(escAsciiString[i])<<4)|
+ pkix_hex2i(escAsciiString[i+1]);
+ testChar2 =
+ (pkix_hex2i(escAsciiString[i+2])<<4)|
+ pkix_hex2i(escAsciiString[i+3]);
+
+ if (charSize == 4) {
+ if ((testChar >= 0xD8)&&
+ (testChar <= 0xDF)) {
+ PKIX_ERROR(PKIX_ILLEGALSURROGATEPAIR);
+ } else if ((testChar == 0x00)&&
+ pkix_isPlaintext(testChar2, debug)) {
+ PKIX_ERROR(
+ PKIX_ILLEGALCHARACTERINESCAPEDASCII);
+ }
+ *destPtr++ = testChar;
+ *destPtr++ = testChar2;
+ } else if (charSize == 8) {
+ /* First two chars must be 0001-0010 */
+ if (!((testChar == 0x00)&&
+ ((testChar2 >= 0x01)&&
+ (testChar2 <= 0x10)))) {
+ PKIX_ERROR(
+ PKIX_ILLEGALCHARACTERINESCAPEDASCII);
+ }
+ /*
+ * Unicode Strings of the form:
+ * x = 0001 0000..0010 FFFF
+ * Encoded as pairs of UTF-16 where
+ * y = ((x - 0001 0000) / 400) + D800
+ * z = ((x - 0001 0000) % 400) + DC00
+ */
+ x -= 0x00010000;
+ y = (x/0x400)+ 0xD800;
+ z = (x%0x400)+ 0xDC00;
+
+ /* Copy four bytes */
+ *destPtr++ = (y&0xFF00)>>8;
+ *destPtr++ = (y&0x00FF);
+ *destPtr++ = (z&0xFF00)>>8;
+ *destPtr++ = (z&0x00FF);
+ }
+ /* Move past the Hex digits and the semi-colon */
+ i += charSize+1;
+ } else {
+ /* Do not allow any other non-plaintext character */
+ PKIX_ERROR(PKIX_ILLEGALCHARACTERINESCAPEDASCII);
+ }
+ }
+
+ *pLength = newLen;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_FREE(*pDest);
+ }
+
+ PKIX_RETURN(STRING);
+}
+
+/*
+ * FUNCTION: pkix_UTF16_to_UTF8
+ * DESCRIPTION:
+ *
+ * Converts array of bytes pointed to by "utf16String" with length of
+ * "utf16Length" into a freshly allocated UTF-8 string and stores a pointer
+ * to that string at "pDest" and stores the string's length at "pLength" (not
+ * counting the null terminator, if requested. The caller is responsible for
+ * freeing "pDest" using PKIX_PL_Free.
+ *
+ * PARAMETERS:
+ * "utf16String"
+ * Address of array of bytes representing data source. Must be non-NULL.
+ * "utf16Length"
+ * Length of data source. Must be even.
+ * "null-term"
+ * Boolean value indicating whether output should be null-terminated.
+ * "pDest"
+ * Address where data will be stored. Must be non-NULL.
+ * "pLength"
+ * Address where data length will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a String Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_UTF16_to_UTF8(
+ const void *utf16String,
+ PKIX_UInt32 utf16Length,
+ PKIX_Boolean null_term,
+ void **pDest,
+ PKIX_UInt32 *pLength,
+ void *plContext)
+{
+ PKIX_Boolean result;
+ PKIX_UInt32 reallocLen;
+ char *endPtr = NULL;
+
+ PKIX_ENTER(STRING, "pkix_UTF16_to_UTF8");
+ PKIX_NULLCHECK_THREE(utf16String, pDest, pLength);
+
+ /* XXX How big can a UTF8 string be compared to a UTF16? */
+ PKIX_CHECK(PKIX_PL_Calloc(1, utf16Length*2, pDest, plContext),
+ PKIX_CALLOCFAILED);
+
+ PKIX_STRING_DEBUG("\tCalling PORT_UCS2_UTF8Conversion).\n");
+ result = PORT_UCS2_UTF8Conversion
+ (PKIX_FALSE, /* False = From UCS2 */
+ (unsigned char *)utf16String,
+ utf16Length,
+ (unsigned char *)*pDest,
+ utf16Length*2, /* Max Size */
+ pLength);
+ if (result == PR_FALSE){
+ PKIX_ERROR(PKIX_PORTUCS2UTF8CONVERSIONFAILED);
+ }
+
+ reallocLen = *pLength;
+
+ if (null_term){
+ reallocLen++;
+ }
+
+ PKIX_CHECK(PKIX_PL_Realloc(*pDest, reallocLen, pDest, plContext),
+ PKIX_REALLOCFAILED);
+
+ if (null_term){
+ endPtr = (char*)*pDest + reallocLen - 1;
+ *endPtr = '\0';
+ }
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_FREE(*pDest);
+ }
+
+ PKIX_RETURN(STRING);
+}
+
+/*
+ * FUNCTION: pkix_UTF8_to_UTF16
+ * DESCRIPTION:
+ *
+ * Converts array of bytes pointed to by "utf8String" with length of
+ * "utf8Length" into a freshly allocated UTF-16 string and stores a pointer
+ * to that string at "pDest" and stores the string's length at "pLength". The
+ * caller is responsible for freeing "pDest" using PKIX_PL_Free.
+ *
+ * PARAMETERS:
+ * "utf8String"
+ * Address of array of bytes representing data source. Must be non-NULL.
+ * "utf8Length"
+ * Length of data source. Must be even.
+ * "pDest"
+ * Address where data will be stored. Must be non-NULL.
+ * "pLength"
+ * Address where data length will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a String Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_UTF8_to_UTF16(
+ const void *utf8String,
+ PKIX_UInt32 utf8Length,
+ void **pDest,
+ PKIX_UInt32 *pLength,
+ void *plContext)
+{
+ PKIX_Boolean result;
+
+ PKIX_ENTER(STRING, "pkix_UTF8_to_UTF16");
+ PKIX_NULLCHECK_THREE(utf8String, pDest, pLength);
+
+ /* XXX How big can a UTF8 string be compared to a UTF16? */
+ PKIX_CHECK(PKIX_PL_Calloc(1, utf8Length*2, pDest, plContext),
+ PKIX_MALLOCFAILED);
+
+ PKIX_STRING_DEBUG("\tCalling PORT_UCS2_UTF8Conversion).\n");
+ result = PORT_UCS2_UTF8Conversion
+ (PKIX_TRUE, /* True = From UTF8 */
+ (unsigned char *)utf8String,
+ utf8Length,
+ (unsigned char *)*pDest,
+ utf8Length*2, /* Max Size */
+ pLength);
+ if (result == PR_FALSE){
+ PKIX_ERROR(PKIX_PORTUCS2UTF8CONVERSIONFAILED);
+ }
+
+ PKIX_CHECK(PKIX_PL_Realloc(*pDest, *pLength, pDest, plContext),
+ PKIX_REALLOCFAILED);
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_FREE(*pDest);
+ }
+
+ PKIX_RETURN(STRING);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_common.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_common.h
new file mode 100755
index 000000000..2946e07a6
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_common.h
@@ -0,0 +1,159 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_common.h
+ *
+ * Common central header file included by all PL source files
+ *
+ */
+
+#ifndef _PKIX_PL_COMMON_H
+#define _PKIX_PL_COMMON_H
+
+/* PKIX HEADERS */
+#include "pkix_tools.h"
+
+/* NSS headers */
+#include "nss.h"
+#include "secport.h"
+#include "secasn1.h"
+#include "secerr.h"
+#include "base64.h"
+#include "cert.h"
+#include "certdb.h"
+#include "genname.h"
+#include "xconst.h"
+#include "keyhi.h"
+#include "ocsp.h"
+#include "ocspt.h"
+#include "pk11pub.h"
+#include "pkcs11.h"
+#include "pkcs11t.h"
+#include "prio.h"
+
+/* NSPR headers */
+#include "nspr.h"
+
+/* private PKIX_PL_NSS system headers */
+#include "pkix_pl_object.h"
+#include "pkix_pl_string.h"
+#ifndef NSS_PKIX_NO_LDAP
+#include "pkix_pl_ldapt.h"
+#endif /* !NSS_PKIX_NO_LDAP */
+#include "pkix_pl_aiamgr.h"
+#include "pkix_pl_bigint.h"
+#include "pkix_pl_oid.h"
+#include "pkix_pl_x500name.h"
+#include "pkix_pl_generalname.h"
+#include "pkix_pl_publickey.h"
+#include "pkix_pl_bytearray.h"
+#include "pkix_pl_date.h"
+#include "pkix_pl_primhash.h"
+#include "pkix_pl_basicconstraints.h"
+#include "pkix_pl_bytearray.h"
+#include "pkix_pl_cert.h"
+#include "pkix_pl_certpolicyinfo.h"
+#include "pkix_pl_certpolicymap.h"
+#include "pkix_pl_certpolicyqualifier.h"
+#include "pkix_pl_crldp.h"
+#include "pkix_pl_crl.h"
+#include "pkix_pl_crlentry.h"
+#include "pkix_pl_nameconstraints.h"
+#include "pkix_pl_ocsprequest.h"
+#include "pkix_pl_ocspresponse.h"
+#include "pkix_pl_pk11certstore.h"
+#include "pkix_pl_socket.h"
+#ifndef NSS_PKIX_NO_LDAP
+#include "pkix_pl_ldapcertstore.h"
+#include "pkix_pl_ldaprequest.h"
+#include "pkix_pl_ldapresponse.h"
+#endif /* !NSS_PKIX_NO_LDAP */
+#include "pkix_pl_nsscontext.h"
+#include "pkix_pl_httpcertstore.h"
+#include "pkix_pl_httpdefaultclient.h"
+#include "pkix_pl_infoaccess.h"
+#include "pkix_sample_modules.h"
+
+#define MAX_DIGITS_32 (PKIX_UInt32) 10
+
+#define PKIX_PL_NSSCALL(type, func, args) \
+ PKIX_ ## type ## _DEBUG_ARG("( Calling %s).\n", #func); \
+ (func args)
+
+#define PKIX_PL_NSSCALLRV(type, lvalue, func, args) \
+ PKIX_ ## type ## _DEBUG_ARG("( Calling %s).\n", #func); \
+ lvalue = (func args)
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_LockObject(
+ PKIX_PL_Object *object,
+ void *plContext);
+
+PKIX_Error *
+pkix_UnlockObject(
+ PKIX_PL_Object *object,
+ void *plContext);
+
+PKIX_Boolean
+pkix_pl_UInt32_Overflows(char *string);
+
+PKIX_Error *
+pkix_pl_helperBytes2Ascii(
+ PKIX_UInt32 *tokens,
+ PKIX_UInt32 numTokens,
+ char **pAscii,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_ipAddrBytes2Ascii(
+ SECItem *secItem,
+ char **pAscii,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_oidBytes2Ascii(
+ SECItem *secItem,
+ char **pAscii,
+ void *plContext);
+
+/* --String-Encoding-Conversion-Functions------------------------ */
+
+PKIX_Error *
+pkix_UTF16_to_EscASCII(
+ const void *utf16String,
+ PKIX_UInt32 utf16Length,
+ PKIX_Boolean debug,
+ char **pDest,
+ PKIX_UInt32 *pLength,
+ void *plContext);
+
+PKIX_Error *
+pkix_EscASCII_to_UTF16(
+ const char *escAsciiString,
+ PKIX_UInt32 escAsciiLen,
+ PKIX_Boolean debug,
+ void **pDest,
+ PKIX_UInt32 *pLength,
+ void *plContext);
+
+PKIX_Error *
+pkix_UTF16_to_UTF8(
+ const void *utf16String,
+ PKIX_UInt32 utf16Length,
+ PKIX_Boolean null_Term,
+ void **pDest,
+ PKIX_UInt32 *pLength,
+ void *plContext);
+
+PKIX_Error *
+pkix_UTF8_to_UTF16(
+ const void *utf8Source,
+ PKIX_UInt32 utf8Length,
+ void **pDest,
+ PKIX_UInt32 *pLength,
+ void *plContext);
+
+#endif /* _PKIX_PL_COMMON_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_error.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_error.c
new file mode 100644
index 000000000..2631aed03
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_error.c
@@ -0,0 +1,26 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_error.c
+ *
+ * PL error functions
+ *
+ */
+
+#include "pkix_pl_common.h"
+
+#undef PKIX_ERRORENTRY
+
+#define PKIX_ERRORENTRY(name,desc,plerr) plerr
+
+const PKIX_Int32 PKIX_PLErrorIndex[] =
+{
+#include "pkix_errorstrings.h"
+};
+
+int
+PKIX_PL_GetPLErrorCode()
+{
+ return PORT_GetError();
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.c
new file mode 100755
index 000000000..260365375
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.c
@@ -0,0 +1,383 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_hashtable.c
+ *
+ * Hashtable Object Functions
+ *
+ */
+
+#include "pkix_pl_hashtable.h"
+
+/* --Private-Structure-------------------------------------------- */
+
+struct PKIX_PL_HashTableStruct {
+ pkix_pl_PrimHashTable *primHash;
+ PKIX_PL_Mutex *tableLock;
+ PKIX_UInt32 maxEntriesPerBucket;
+};
+
+/* --Private-Functions-------------------------------------------- */
+
+#define PKIX_MUTEX_UNLOCK(mutex) \
+ do { \
+ if (mutex && lockedMutex == (PKIX_PL_Mutex *)(mutex)) { \
+ pkixTempResult = \
+ PKIX_PL_Mutex_Unlock((mutex), plContext); \
+ PORT_Assert(pkixTempResult == NULL); \
+ if (pkixTempResult) { \
+ PKIX_DoAddError(&stdVars, pkixTempResult, plContext); \
+ pkixTempResult = NULL; \
+ } \
+ lockedMutex = NULL; \
+ } else { \
+ PORT_Assert(lockedMutex == NULL); \
+ }\
+ } while (0)
+
+
+#define PKIX_MUTEX_LOCK(mutex) \
+ do { \
+ if (mutex){ \
+ PORT_Assert(lockedMutex == NULL); \
+ PKIX_CHECK(PKIX_PL_Mutex_Lock((mutex), plContext), \
+ PKIX_MUTEXLOCKFAILED); \
+ lockedMutex = (mutex); \
+ } \
+ } while (0)
+
+/*
+ * FUNCTION: pkix_pl_HashTable_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_HashTable_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_HashTable *ht = NULL;
+ pkix_pl_HT_Elem *item = NULL;
+ PKIX_UInt32 i;
+
+ PKIX_ENTER(HASHTABLE, "pkix_pl_HashTable_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_HASHTABLE_TYPE, plContext),
+ PKIX_OBJECTNOTHASHTABLE);
+
+ ht = (PKIX_PL_HashTable*) object;
+
+ /* DecRef every object in the primitive hash table */
+ for (i = 0; i < ht->primHash->size; i++) {
+ for (item = ht->primHash->buckets[i];
+ item != NULL;
+ item = item->next) {
+ PKIX_DECREF(item->key);
+ PKIX_DECREF(item->value);
+ }
+ }
+
+ PKIX_CHECK(pkix_pl_PrimHashTable_Destroy(ht->primHash, plContext),
+ PKIX_PRIMHASHTABLEDESTROYFAILED);
+
+ PKIX_DECREF(ht->tableLock);
+
+cleanup:
+
+ PKIX_RETURN(HASHTABLE);
+}
+
+/*
+ * FUNCTION: pkix_pl_HashTable_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_HASHTABLE_TYPE and its related functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_HashTable_RegisterSelf(
+ void *plContext)
+{
+
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(HASHTABLE, "pkix_pl_HashTable_RegisterSelf");
+
+ entry.description = "HashTable";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_HashTable);
+ entry.destructor = pkix_pl_HashTable_Destroy;
+ entry.equalsFunction = NULL;
+ entry.hashcodeFunction = NULL;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = NULL;
+
+ systemClasses[PKIX_HASHTABLE_TYPE] = entry;
+
+ PKIX_RETURN(HASHTABLE);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_HashTable_Create (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_HashTable_Create(
+ PKIX_UInt32 numBuckets,
+ PKIX_UInt32 maxEntriesPerBucket,
+ PKIX_PL_HashTable **pResult,
+ void *plContext)
+{
+ PKIX_PL_HashTable *hashTable = NULL;
+
+ PKIX_ENTER(HASHTABLE, "PKIX_PL_HashTable_Create");
+ PKIX_NULLCHECK_ONE(pResult);
+
+ if (numBuckets == 0) {
+ PKIX_ERROR(PKIX_NUMBUCKETSEQUALSZERO);
+ }
+
+ /* Allocate a new hashtable */
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_HASHTABLE_TYPE,
+ sizeof (PKIX_PL_HashTable),
+ (PKIX_PL_Object **)&hashTable,
+ plContext),
+ PKIX_COULDNOTCREATEHASHTABLEOBJECT);
+
+ /* Create the underlying primitive hash table type */
+ PKIX_CHECK(pkix_pl_PrimHashTable_Create
+ (numBuckets, &hashTable->primHash, plContext),
+ PKIX_PRIMHASHTABLECREATEFAILED);
+
+ /* Create a lock for this table */
+ PKIX_CHECK(PKIX_PL_Mutex_Create(&hashTable->tableLock, plContext),
+ PKIX_ERRORCREATINGTABLELOCK);
+
+ hashTable->maxEntriesPerBucket = maxEntriesPerBucket;
+
+ *pResult = hashTable;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(hashTable);
+ }
+
+ PKIX_RETURN(HASHTABLE);
+}
+
+/*
+ * FUNCTION: PKIX_PL_HashTable_Add (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_HashTable_Add(
+ PKIX_PL_HashTable *ht,
+ PKIX_PL_Object *key,
+ PKIX_PL_Object *value,
+ void *plContext)
+{
+ PKIX_PL_Mutex *lockedMutex = NULL;
+ PKIX_PL_Object *deletedKey = NULL;
+ PKIX_PL_Object *deletedValue = NULL;
+ PKIX_UInt32 hashCode;
+ PKIX_PL_EqualsCallback keyComp;
+ PKIX_UInt32 bucketSize = 0;
+
+ PKIX_ENTER(HASHTABLE, "PKIX_PL_HashTable_Add");
+
+#if !defined(PKIX_OBJECT_LEAK_TEST)
+ PKIX_NULLCHECK_THREE(ht, key, value);
+#else
+ PKIX_NULLCHECK_TWO(key, value);
+
+ if (ht == NULL) {
+ PKIX_RETURN(HASHTABLE);
+ }
+#endif
+ /* Insert into primitive hashtable */
+
+ PKIX_CHECK(PKIX_PL_Object_Hashcode(key, &hashCode, plContext),
+ PKIX_OBJECTHASHCODEFAILED);
+
+ PKIX_CHECK(pkix_pl_Object_RetrieveEqualsCallback
+ (key, &keyComp, plContext),
+ PKIX_OBJECTRETRIEVEEQUALSCALLBACKFAILED);
+
+ PKIX_MUTEX_LOCK(ht->tableLock);
+
+ PKIX_CHECK(pkix_pl_PrimHashTable_GetBucketSize
+ (ht->primHash,
+ hashCode,
+ &bucketSize,
+ plContext),
+ PKIX_PRIMHASHTABLEGETBUCKETSIZEFAILED);
+
+ if (ht->maxEntriesPerBucket != 0 &&
+ bucketSize >= ht->maxEntriesPerBucket) {
+ /* drop the last one in the bucket */
+ PKIX_CHECK(pkix_pl_PrimHashTable_RemoveFIFO
+ (ht->primHash,
+ hashCode,
+ (void **) &deletedKey,
+ (void **) &deletedValue,
+ plContext),
+ PKIX_PRIMHASHTABLEGETBUCKETSIZEFAILED);
+ PKIX_DECREF(deletedKey);
+ PKIX_DECREF(deletedValue);
+ }
+
+ PKIX_CHECK(pkix_pl_PrimHashTable_Add
+ (ht->primHash,
+ (void *)key,
+ (void *)value,
+ hashCode,
+ keyComp,
+ plContext),
+ PKIX_PRIMHASHTABLEADDFAILED);
+
+ PKIX_INCREF(key);
+ PKIX_INCREF(value);
+ PKIX_MUTEX_UNLOCK(ht->tableLock);
+
+ /*
+ * we don't call PKIX_PL_InvalidateCache here b/c we have
+ * not implemented toString or hashcode for this Object
+ */
+
+cleanup:
+
+ PKIX_MUTEX_UNLOCK(ht->tableLock);
+
+ PKIX_RETURN(HASHTABLE);
+}
+
+/*
+ * FUNCTION: PKIX_PL_HashTable_Remove (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_HashTable_Remove(
+ PKIX_PL_HashTable *ht,
+ PKIX_PL_Object *key,
+ void *plContext)
+{
+ PKIX_PL_Mutex *lockedMutex = NULL;
+ PKIX_PL_Object *origKey = NULL;
+ PKIX_PL_Object *value = NULL;
+ PKIX_UInt32 hashCode;
+ PKIX_PL_EqualsCallback keyComp;
+
+ PKIX_ENTER(HASHTABLE, "PKIX_PL_HashTable_Remove");
+
+#if !defined(PKIX_OBJECT_LEAK_TEST)
+ PKIX_NULLCHECK_TWO(ht, key);
+#else
+ PKIX_NULLCHECK_ONE(key);
+
+ if (ht == NULL) {
+ PKIX_RETURN(HASHTABLE);
+ }
+#endif
+
+ PKIX_CHECK(PKIX_PL_Object_Hashcode(key, &hashCode, plContext),
+ PKIX_OBJECTHASHCODEFAILED);
+
+ PKIX_CHECK(pkix_pl_Object_RetrieveEqualsCallback
+ (key, &keyComp, plContext),
+ PKIX_OBJECTRETRIEVEEQUALSCALLBACKFAILED);
+
+ PKIX_MUTEX_LOCK(ht->tableLock);
+
+ /* Remove from primitive hashtable */
+ PKIX_CHECK(pkix_pl_PrimHashTable_Remove
+ (ht->primHash,
+ (void *)key,
+ hashCode,
+ keyComp,
+ (void **)&origKey,
+ (void **)&value,
+ plContext),
+ PKIX_PRIMHASHTABLEREMOVEFAILED);
+
+ PKIX_MUTEX_UNLOCK(ht->tableLock);
+
+ PKIX_DECREF(origKey);
+ PKIX_DECREF(value);
+
+ /*
+ * we don't call PKIX_PL_InvalidateCache here b/c we have
+ * not implemented toString or hashcode for this Object
+ */
+
+cleanup:
+
+ PKIX_MUTEX_UNLOCK(ht->tableLock);
+
+ PKIX_RETURN(HASHTABLE);
+}
+
+/*
+ * FUNCTION: PKIX_PL_HashTable_Lookup (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_HashTable_Lookup(
+ PKIX_PL_HashTable *ht,
+ PKIX_PL_Object *key,
+ PKIX_PL_Object **pResult,
+ void *plContext)
+{
+ PKIX_PL_Mutex *lockedMutex = NULL;
+ PKIX_UInt32 hashCode;
+ PKIX_PL_EqualsCallback keyComp;
+ PKIX_PL_Object *result = NULL;
+
+ PKIX_ENTER(HASHTABLE, "PKIX_PL_HashTable_Lookup");
+
+#if !defined(PKIX_OBJECT_LEAK_TEST)
+ PKIX_NULLCHECK_THREE(ht, key, pResult);
+#else
+ PKIX_NULLCHECK_TWO(key, pResult);
+
+ if (ht == NULL) {
+ PKIX_RETURN(HASHTABLE);
+ }
+#endif
+
+ PKIX_CHECK(PKIX_PL_Object_Hashcode(key, &hashCode, plContext),
+ PKIX_OBJECTHASHCODEFAILED);
+
+ PKIX_CHECK(pkix_pl_Object_RetrieveEqualsCallback
+ (key, &keyComp, plContext),
+ PKIX_OBJECTRETRIEVEEQUALSCALLBACKFAILED);
+
+ PKIX_MUTEX_LOCK(ht->tableLock);
+
+ /* Lookup in primitive hashtable */
+ PKIX_CHECK(pkix_pl_PrimHashTable_Lookup
+ (ht->primHash,
+ (void *)key,
+ hashCode,
+ keyComp,
+ (void **)&result,
+ plContext),
+ PKIX_PRIMHASHTABLELOOKUPFAILED);
+
+ PKIX_INCREF(result);
+ PKIX_MUTEX_UNLOCK(ht->tableLock);
+
+ *pResult = result;
+
+cleanup:
+
+ PKIX_MUTEX_UNLOCK(ht->tableLock);
+
+ PKIX_RETURN(HASHTABLE);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.h
new file mode 100755
index 000000000..479c62373
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_hashtable.h
@@ -0,0 +1,29 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_hashtable.h
+ *
+ * Hashtable Object Definition
+ *
+ */
+
+#ifndef _PKIX_PL_HASHTABLE_H
+#define _PKIX_PL_HASHTABLE_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_pl_HashTable_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_HASHTABLE_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_lifecycle.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_lifecycle.c
new file mode 100755
index 000000000..70ed25d72
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_lifecycle.c
@@ -0,0 +1,279 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_lifecycle.c
+ *
+ * Lifecycle Functions for the PKIX PL library.
+ *
+ */
+
+#include "pkix_pl_lifecycle.h"
+
+PKIX_Boolean pkix_pl_initialized = PKIX_FALSE;
+pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+PRLock *classTableLock;
+PRLogModuleInfo *pkixLog = NULL;
+
+/*
+ * PKIX_ALLOC_ERROR is a special error object hard-coded into the
+ * pkix_error.o object file. It is thrown if system memory cannot be
+ * allocated. PKIX_ALLOC_ERROR is immutable.
+ * IncRef, DecRef, and Settor functions cannot be called.
+ */
+
+/* Keep this structure definition here for its is used only once here */
+struct PKIX_Alloc_Error_ObjectStruct {
+ PKIX_PL_Object header;
+ PKIX_Error error;
+};
+typedef struct PKIX_Alloc_Error_ObjectStruct PKIX_Alloc_Error_Object;
+
+static const PKIX_Alloc_Error_Object pkix_Alloc_Error_Data = {
+ {
+ PKIX_MAGIC_HEADER, /* PRUint64 magicHeader */
+ (PKIX_UInt32)PKIX_ERROR_TYPE, /* PKIX_UInt32 type */
+ (PKIX_UInt32)1, /* PKIX_UInt32 references */
+ /* Warning! Cannot Ref Count with NULL lock */
+ (void *)0, /* PRLock *lock */
+ (PKIX_PL_String *)0, /* PKIX_PL_String *stringRep */
+ (PKIX_UInt32)0, /* PKIX_UInt32 hashcode */
+ (PKIX_Boolean)PKIX_FALSE, /* PKIX_Boolean hashcodeCached */
+ }, {
+ (PKIX_ERRORCODE)0, /* PKIX_ERRORCODE errCode; */
+ (PKIX_ERRORCLASS)PKIX_FATAL_ERROR,/* PKIX_ERRORCLASS errClass */
+ (PKIX_UInt32)SEC_ERROR_LIBPKIX_INTERNAL, /* default PL Error Code */
+ (PKIX_Error *)0, /* PKIX_Error *cause */
+ (PKIX_PL_Object *)0, /* PKIX_PL_Object *info */
+ }
+};
+
+PKIX_Error* PKIX_ALLOC_ERROR(void)
+{
+ return (PKIX_Error *)&pkix_Alloc_Error_Data.error;
+}
+
+#ifdef PKIX_OBJECT_LEAK_TEST
+SECStatus
+pkix_pl_lifecycle_ObjectTableUpdate(int *objCountTable)
+{
+ int typeCounter = 0;
+
+ for (; typeCounter < PKIX_NUMTYPES; typeCounter++) {
+ pkix_ClassTable_Entry *entry = &systemClasses[typeCounter];
+
+ objCountTable[typeCounter] = entry->objCounter;
+ }
+
+ return SECSuccess;
+}
+#endif /* PKIX_OBJECT_LEAK_TEST */
+
+
+PKIX_UInt32
+pkix_pl_lifecycle_ObjectLeakCheck(int *initObjCountTable)
+{
+ unsigned int typeCounter = 0;
+ PKIX_UInt32 numObjects = 0;
+ char classNameBuff[128];
+ char *className = NULL;
+
+ for (; typeCounter < PKIX_NUMTYPES; typeCounter++) {
+ pkix_ClassTable_Entry *entry = &systemClasses[typeCounter];
+ PKIX_UInt32 objCountDiff = entry->objCounter;
+
+ if (initObjCountTable) {
+ PKIX_UInt32 initialCount = initObjCountTable[typeCounter];
+ objCountDiff = (entry->objCounter > initialCount) ?
+ entry->objCounter - initialCount : 0;
+ }
+
+ numObjects += objCountDiff;
+
+ if (!pkixLog || !objCountDiff) {
+ continue;
+ }
+ className = entry->description;
+ if (!className) {
+ className = classNameBuff;
+ PR_snprintf(className, 128, "Unknown(ref %d)",
+ entry->objCounter);
+ }
+
+ PR_LOG(pkixLog, 1, ("Class %s leaked %d objects of "
+ "size %d bytes, total = %d bytes\n", className,
+ objCountDiff, entry->typeObjectSize,
+ objCountDiff * entry->typeObjectSize));
+ }
+
+ return numObjects;
+}
+
+/*
+ * PKIX_PL_Initialize (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Initialize(
+ PKIX_Boolean platformInitNeeded,
+ PKIX_Boolean useArenas,
+ void **pPlContext)
+{
+ void *plContext = NULL;
+
+ PKIX_ENTER(OBJECT, "PKIX_PL_Initialize");
+
+ /*
+ * This function can only be called once. If it has already been
+ * called, we return a positive status.
+ */
+ if (pkix_pl_initialized) {
+ PKIX_RETURN(OBJECT);
+ }
+
+ classTableLock = PR_NewLock();
+ if (classTableLock == NULL) {
+ return PKIX_ALLOC_ERROR();
+ }
+
+ if (PR_GetEnvSecure("NSS_STRICT_SHUTDOWN")) {
+ pkixLog = PR_NewLogModule("pkix");
+ }
+ /*
+ * Register Object, it is the base object of all other objects.
+ */
+ pkix_pl_Object_RegisterSelf(plContext);
+
+ /*
+ * Register Error and String, since they will be needed if
+ * there is a problem in registering any other type.
+ */
+ pkix_Error_RegisterSelf(plContext);
+ pkix_pl_String_RegisterSelf(plContext);
+
+
+ /*
+ * We register all other system types
+ * (They don't need to be in order, but it's
+ * easier to keep track of what types are registered
+ * if we register them in the same order as their
+ * numbers, defined in pkixt.h.
+ */
+ pkix_pl_BigInt_RegisterSelf(plContext); /* 1-10 */
+ pkix_pl_ByteArray_RegisterSelf(plContext);
+ pkix_pl_HashTable_RegisterSelf(plContext);
+ pkix_List_RegisterSelf(plContext);
+ pkix_Logger_RegisterSelf(plContext);
+ pkix_pl_Mutex_RegisterSelf(plContext);
+ pkix_pl_OID_RegisterSelf(plContext);
+ pkix_pl_RWLock_RegisterSelf(plContext);
+
+ pkix_pl_CertBasicConstraints_RegisterSelf(plContext); /* 11-20 */
+ pkix_pl_Cert_RegisterSelf(plContext);
+ pkix_pl_CRL_RegisterSelf(plContext);
+ pkix_pl_CRLEntry_RegisterSelf(plContext);
+ pkix_pl_Date_RegisterSelf(plContext);
+ pkix_pl_GeneralName_RegisterSelf(plContext);
+ pkix_pl_CertNameConstraints_RegisterSelf(plContext);
+ pkix_pl_PublicKey_RegisterSelf(plContext);
+ pkix_TrustAnchor_RegisterSelf(plContext);
+
+ pkix_pl_X500Name_RegisterSelf(plContext); /* 21-30 */
+ pkix_pl_HttpCertStoreContext_RegisterSelf(plContext);
+ pkix_BuildResult_RegisterSelf(plContext);
+ pkix_ProcessingParams_RegisterSelf(plContext);
+ pkix_ValidateParams_RegisterSelf(plContext);
+ pkix_ValidateResult_RegisterSelf(plContext);
+ pkix_CertStore_RegisterSelf(plContext);
+ pkix_CertChainChecker_RegisterSelf(plContext);
+ pkix_RevocationChecker_RegisterSelf(plContext);
+ pkix_CertSelector_RegisterSelf(plContext);
+
+ pkix_ComCertSelParams_RegisterSelf(plContext); /* 31-40 */
+ pkix_CRLSelector_RegisterSelf(plContext);
+ pkix_ComCRLSelParams_RegisterSelf(plContext);
+ pkix_pl_CertPolicyInfo_RegisterSelf(plContext);
+ pkix_pl_CertPolicyQualifier_RegisterSelf(plContext);
+ pkix_pl_CertPolicyMap_RegisterSelf(plContext);
+ pkix_PolicyNode_RegisterSelf(plContext);
+ pkix_TargetCertCheckerState_RegisterSelf(plContext);
+ pkix_BasicConstraintsCheckerState_RegisterSelf(plContext);
+ pkix_PolicyCheckerState_RegisterSelf(plContext);
+
+ pkix_pl_CollectionCertStoreContext_RegisterSelf(plContext); /* 41-50 */
+ pkix_CrlChecker_RegisterSelf(plContext);
+ pkix_ForwardBuilderState_RegisterSelf(plContext);
+ pkix_SignatureCheckerState_RegisterSelf(plContext);
+ pkix_NameConstraintsCheckerState_RegisterSelf(plContext);
+#ifndef NSS_PKIX_NO_LDAP
+ pkix_pl_LdapRequest_RegisterSelf(plContext);
+ pkix_pl_LdapResponse_RegisterSelf(plContext);
+ pkix_pl_LdapDefaultClient_RegisterSelf(plContext);
+#endif
+ pkix_pl_Socket_RegisterSelf(plContext);
+
+ pkix_ResourceLimits_RegisterSelf(plContext); /* 51-59 */
+ pkix_pl_MonitorLock_RegisterSelf(plContext);
+ pkix_pl_InfoAccess_RegisterSelf(plContext);
+ pkix_pl_AIAMgr_RegisterSelf(plContext);
+ pkix_OcspChecker_RegisterSelf(plContext);
+ pkix_pl_OcspCertID_RegisterSelf(plContext);
+ pkix_pl_OcspRequest_RegisterSelf(plContext);
+ pkix_pl_OcspResponse_RegisterSelf(plContext);
+ pkix_pl_HttpDefaultClient_RegisterSelf(plContext);
+ pkix_VerifyNode_RegisterSelf(plContext);
+ pkix_EkuChecker_RegisterSelf(plContext);
+ pkix_pl_CrlDp_RegisterSelf(plContext);
+
+ if (pPlContext) {
+ PKIX_CHECK(PKIX_PL_NssContext_Create
+ (0, useArenas, NULL, &plContext),
+ PKIX_NSSCONTEXTCREATEFAILED);
+
+ *pPlContext = plContext;
+ }
+
+ pkix_pl_initialized = PKIX_TRUE;
+
+cleanup:
+
+ PKIX_RETURN(OBJECT);
+}
+
+/*
+ * PKIX_PL_Shutdown (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Shutdown(void *plContext)
+{
+#ifdef DEBUG
+ PKIX_UInt32 numLeakedObjects = 0;
+#endif
+
+ PKIX_ENTER(OBJECT, "PKIX_PL_Shutdown");
+
+ if (!pkix_pl_initialized) {
+ /* The library was not initilized */
+ PKIX_RETURN(OBJECT);
+ }
+
+ PR_DestroyLock(classTableLock);
+
+ pkix_pl_HttpCertStore_Shutdown(plContext);
+
+#ifdef DEBUG
+ numLeakedObjects = pkix_pl_lifecycle_ObjectLeakCheck(NULL);
+ if (PR_GetEnvSecure("NSS_STRICT_SHUTDOWN")) {
+ PORT_Assert(numLeakedObjects == 0);
+ }
+#else
+ pkix_pl_lifecycle_ObjectLeakCheck(NULL);
+#endif
+
+ if (plContext != NULL) {
+ PKIX_PL_NssContext_Destroy(plContext);
+ }
+
+ pkix_pl_initialized = PKIX_FALSE;
+
+ PKIX_RETURN(OBJECT);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_lifecycle.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_lifecycle.h
new file mode 100755
index 000000000..9660af123
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_lifecycle.h
@@ -0,0 +1,91 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_lifecycle.h
+ *
+ * Lifecycle Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_LIFECYCLE_H
+#define _PKIX_PL_LIFECYCLE_H
+
+#include "pkix_pl_common.h"
+#include "pkix_pl_oid.h"
+#include "pkix_pl_aiamgr.h"
+#include "pkix_pl_bigint.h"
+#include "pkix_pl_bytearray.h"
+#include "pkix_pl_hashtable.h"
+#include "pkix_pl_mutex.h"
+#include "pkix_pl_rwlock.h"
+#include "pkix_pl_monitorlock.h"
+#include "pkix_pl_string.h"
+#include "pkix_pl_cert.h"
+#include "pkix_pl_x500name.h"
+#include "pkix_pl_generalname.h"
+#include "pkix_pl_publickey.h"
+#include "pkix_pl_date.h"
+#include "pkix_pl_basicconstraints.h"
+#include "pkix_pl_certpolicyinfo.h"
+#include "pkix_pl_certpolicymap.h"
+#include "pkix_pl_certpolicyqualifier.h"
+#include "pkix_pl_crlentry.h"
+#include "pkix_pl_crl.h"
+#include "pkix_pl_colcertstore.h"
+#ifndef NSS_PKIX_NO_LDAP
+#include "pkix_pl_ldapcertstore.h"
+#include "pkix_pl_ldapdefaultclient.h"
+#include "pkix_pl_ldaprequest.h"
+#include "pkix_pl_ldapresponse.h"
+#endif /* !NSS_PKIX_NO_LDAP */
+#include "pkix_pl_socket.h"
+#include "pkix_pl_infoaccess.h"
+#include "pkix_store.h"
+#include "pkix_error.h"
+#include "pkix_logger.h"
+#include "pkix_list.h"
+#include "pkix_trustanchor.h"
+#include "pkix_procparams.h"
+#include "pkix_valparams.h"
+#include "pkix_valresult.h"
+#include "pkix_verifynode.h"
+#include "pkix_resourcelimits.h"
+#include "pkix_certchainchecker.h"
+#include "pkix_revocationchecker.h"
+#include "pkix_certselector.h"
+#include "pkix_comcertselparams.h"
+#include "pkix_crlselector.h"
+#include "pkix_comcrlselparams.h"
+#include "pkix_targetcertchecker.h"
+#include "pkix_basicconstraintschecker.h"
+#include "pkix_policynode.h"
+#include "pkix_policychecker.h"
+#include "pkix_crlchecker.h"
+#include "pkix_signaturechecker.h"
+#include "pkix_buildresult.h"
+#include "pkix_build.h"
+#include "pkix_pl_nameconstraints.h"
+#include "pkix_nameconstraintschecker.h"
+#include "pkix_ocspchecker.h"
+#include "pkix_pl_ocspcertid.h"
+#include "pkix_pl_ocsprequest.h"
+#include "pkix_pl_ocspresponse.h"
+#include "pkix_pl_httpdefaultclient.h"
+#include "pkix_pl_httpcertstore.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_InitializeParamsStruct {
+ PKIX_List *loggers;
+ PKIX_UInt32 majorVersion;
+ PKIX_UInt32 minorVersion;
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_LIFECYCLE_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mem.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mem.c
new file mode 100755
index 000000000..d75c0be26
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mem.c
@@ -0,0 +1,168 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_mem.c
+ *
+ * Memory Management Functions
+ *
+ */
+
+#include "pkix_pl_mem.h"
+
+/*
+ * FUNCTION: PKIX_PL_Malloc (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Malloc(
+ PKIX_UInt32 size,
+ void **pMemory,
+ void *plContext)
+{
+ PKIX_PL_NssContext *nssContext = NULL;
+ void *result = NULL;
+
+ PKIX_ENTER(MEM, "PKIX_PL_Malloc");
+ PKIX_NULLCHECK_ONE(pMemory);
+
+ if (size == 0){
+ *pMemory = NULL;
+ } else {
+
+ nssContext = (PKIX_PL_NssContext *)plContext;
+
+ if (nssContext != NULL && nssContext->arena != NULL) {
+ PKIX_MEM_DEBUG("\tCalling PORT_ArenaAlloc.\n");
+ *pMemory = PORT_ArenaAlloc(nssContext->arena, size);
+ } else {
+ PKIX_MEM_DEBUG("\tCalling PR_Malloc.\n");
+ result = (void *) PR_Malloc(size);
+
+ if (result == NULL) {
+ PKIX_MEM_DEBUG("Fatal Error Occurred: "
+ "PR_Malloc failed.\n");
+ PKIX_ERROR_ALLOC_ERROR();
+ } else {
+ *pMemory = result;
+ }
+ }
+ }
+
+cleanup:
+ PKIX_RETURN(MEM);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Calloc (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Calloc(
+ PKIX_UInt32 nElem,
+ PKIX_UInt32 elSize,
+ void **pMemory,
+ void *plContext)
+{
+ PKIX_PL_NssContext *nssContext = NULL;
+ void *result = NULL;
+
+ PKIX_ENTER(MEM, "PKIX_PL_Calloc");
+ PKIX_NULLCHECK_ONE(pMemory);
+
+ if ((nElem == 0) || (elSize == 0)){
+ *pMemory = NULL;
+ } else {
+
+ nssContext = (PKIX_PL_NssContext *)plContext;
+
+ if (nssContext != NULL && nssContext->arena != NULL) {
+ PKIX_MEM_DEBUG("\tCalling PORT_ArenaAlloc.\n");
+ *pMemory = PORT_ArenaAlloc(nssContext->arena, elSize);
+ } else {
+ PKIX_MEM_DEBUG("\tCalling PR_Calloc.\n");
+ result = (void *) PR_Calloc(nElem, elSize);
+
+ if (result == NULL) {
+ PKIX_MEM_DEBUG("Fatal Error Occurred: "
+ "PR_Calloc failed.\n");
+ PKIX_ERROR_ALLOC_ERROR();
+ } else {
+ *pMemory = result;
+ }
+ }
+ }
+
+cleanup:
+
+ PKIX_RETURN(MEM);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Realloc (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Realloc(
+ void *ptr,
+ PKIX_UInt32 size,
+ void **pMemory,
+ void *plContext)
+{
+ PKIX_PL_NssContext *nssContext = NULL;
+ void *result = NULL;
+
+ PKIX_ENTER(MEM, "PKIX_PL_Realloc");
+ PKIX_NULLCHECK_ONE(pMemory);
+
+ nssContext = (PKIX_PL_NssContext *)plContext;
+
+ if (nssContext != NULL && nssContext->arena != NULL) {
+ PKIX_MEM_DEBUG("\tCalling PORT_ArenaAlloc.\n");
+ result = PORT_ArenaAlloc(nssContext->arena, size);
+
+ if (result){
+ PKIX_MEM_DEBUG("\tCalling PORT_Memcpy.\n");
+ PORT_Memcpy(result, ptr, size);
+ }
+ *pMemory = result;
+ } else {
+ PKIX_MEM_DEBUG("\tCalling PR_Realloc.\n");
+ result = (void *) PR_Realloc(ptr, size);
+
+ if (result == NULL) {
+ if (size == 0){
+ *pMemory = NULL;
+ } else {
+ PKIX_MEM_DEBUG
+ ("Fatal Error Occurred: "
+ "PR_Realloc failed.\n");
+ PKIX_ERROR_ALLOC_ERROR();
+ }
+ } else {
+ *pMemory = result;
+ }
+ }
+
+cleanup:
+
+ PKIX_RETURN(MEM);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Free (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Free(
+ void *ptr,
+ /* ARGSUSED */ void *plContext)
+{
+ PKIX_PL_NssContext *context = NULL;
+
+ PKIX_ENTER(MEM, "PKIX_PL_Free");
+
+ context = (PKIX_PL_NssContext *) plContext;
+ if (context == NULL || context->arena == NULL) {
+ PKIX_MEM_DEBUG("\tCalling PR_Free.\n");
+ (void) PR_Free(ptr);
+ }
+
+ PKIX_RETURN(MEM);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mem.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mem.h
new file mode 100755
index 000000000..eaec6246c
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mem.h
@@ -0,0 +1,24 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_mem.h
+ *
+ * Memory Management Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_MEM_H
+#define _PKIX_PL_MEM_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_MEM_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_monitorlock.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_monitorlock.c
new file mode 100755
index 000000000..a5d2fc962
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_monitorlock.c
@@ -0,0 +1,136 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_monitorlock.c
+ *
+ * Read/Write Lock Functions
+ *
+ */
+
+#include "pkix_pl_monitorlock.h"
+
+/* --Private-Functions-------------------------------------------- */
+
+static PKIX_Error *
+pkix_pl_MonitorLock_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_MonitorLock* monitorLock = NULL;
+
+ PKIX_ENTER(MONITORLOCK, "pkix_pl_MonitorLock_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_MONITORLOCK_TYPE, plContext),
+ PKIX_OBJECTNOTMONITORLOCK);
+
+ monitorLock = (PKIX_PL_MonitorLock*) object;
+
+ PKIX_MONITORLOCK_DEBUG("Calling PR_DestroyMonitor)\n");
+ PR_DestroyMonitor(monitorLock->lock);
+ monitorLock->lock = NULL;
+
+cleanup:
+
+ PKIX_RETURN(MONITORLOCK);
+}
+
+/*
+ * FUNCTION: pkix_pl_MonitorLock_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_MONITORLOCK_TYPE and its related functions with
+ * systemClasses[].
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_MonitorLock_RegisterSelf(
+ void *plContext)
+{
+
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(MONITORLOCK, "pkix_pl_MonitorLock_RegisterSelf");
+
+ entry.description = "MonitorLock";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_MonitorLock);
+ entry.destructor = pkix_pl_MonitorLock_Destroy;
+ entry.equalsFunction = NULL;
+ entry.hashcodeFunction = NULL;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = NULL;
+
+ systemClasses[PKIX_MONITORLOCK_TYPE] = entry;
+
+ PKIX_RETURN(MONITORLOCK);
+}
+
+/* --Public-Functions--------------------------------------------- */
+
+PKIX_Error *
+PKIX_PL_MonitorLock_Create(
+ PKIX_PL_MonitorLock **pNewLock,
+ void *plContext)
+{
+ PKIX_PL_MonitorLock *monitorLock = NULL;
+
+ PKIX_ENTER(MONITORLOCK, "PKIX_PL_MonitorLock_Create");
+ PKIX_NULLCHECK_ONE(pNewLock);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_MONITORLOCK_TYPE,
+ sizeof (PKIX_PL_MonitorLock),
+ (PKIX_PL_Object **)&monitorLock,
+ plContext),
+ PKIX_ERRORALLOCATINGMONITORLOCK);
+
+ PKIX_MONITORLOCK_DEBUG("\tCalling PR_NewMonitor)\n");
+ monitorLock->lock = PR_NewMonitor();
+
+ if (monitorLock->lock == NULL) {
+ PKIX_DECREF(monitorLock);
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ *pNewLock = monitorLock;
+
+cleanup:
+
+ PKIX_RETURN(MONITORLOCK);
+}
+
+PKIX_Error *
+PKIX_PL_MonitorLock_Enter(
+ PKIX_PL_MonitorLock *monitorLock,
+ void *plContext)
+{
+ PKIX_ENTER_NO_LOGGER(MONITORLOCK, "PKIX_PL_MonitorLock_Enter");
+ PKIX_NULLCHECK_ONE(monitorLock);
+
+ PKIX_MONITORLOCK_DEBUG("\tCalling PR_EnterMonitor)\n");
+ (void) PR_EnterMonitor(monitorLock->lock);
+
+ PKIX_RETURN_NO_LOGGER(MONITORLOCK);
+}
+
+PKIX_Error *
+PKIX_PL_MonitorLock_Exit(
+ PKIX_PL_MonitorLock *monitorLock,
+ void *plContext)
+{
+ PKIX_ENTER_NO_LOGGER(MONITORLOCK, "PKIX_PL_MonitorLock_Exit");
+ PKIX_NULLCHECK_ONE(monitorLock);
+
+ PKIX_MONITORLOCK_DEBUG("\tCalling PR_ExitMonitor)\n");
+ PR_ExitMonitor(monitorLock->lock);
+
+ PKIX_RETURN_NO_LOGGER(MONITORLOCK);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_monitorlock.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_monitorlock.h
new file mode 100755
index 000000000..76ac539ad
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_monitorlock.h
@@ -0,0 +1,33 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_monitorlock.h
+ *
+ * Read/Write Lock Definition
+ *
+ */
+
+#ifndef _PKIX_PL_MONITORLOCK_H
+#define _PKIX_PL_MONITORLOCK_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_MonitorLockStruct {
+ PRMonitor* lock;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_pl_MonitorLock_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_MONITORLOCK_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mutex.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mutex.c
new file mode 100755
index 000000000..07d13695b
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mutex.c
@@ -0,0 +1,163 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_mutex.c
+ *
+ * Mutual Exclusion (Lock) Object Functions
+ *
+ */
+
+#include "pkix_pl_mutex.h"
+
+/* --Private-Functions-------------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_Mutex_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_Mutex_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_Mutex *mutex = NULL;
+
+ PKIX_ENTER(MUTEX, "pkix_pl_Mutex_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ /* Sanity check: Test that "object" is a mutex */
+ PKIX_CHECK(pkix_CheckType(object, PKIX_MUTEX_TYPE, plContext),
+ PKIX_OBJECTNOTMUTEX);
+
+ mutex = (PKIX_PL_Mutex*) object;
+
+ PKIX_MUTEX_DEBUG("\tCalling PR_DestroyLock).\n");
+ PR_DestroyLock(mutex->lock);
+ mutex->lock = NULL;
+
+cleanup:
+
+ PKIX_RETURN(MUTEX);
+}
+
+/*
+ * FUNCTION: pkix_pl_Mutex_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_MUTEX_TYPE and its related functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_Mutex_RegisterSelf(
+ /* ARGSUSED */ void *plContext)
+{
+
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(MUTEX, "pkix_pl_Mutex_RegisterSelf");
+
+ entry.description = "Mutex";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_Mutex);
+ entry.destructor = pkix_pl_Mutex_Destroy;
+ entry.equalsFunction = NULL;
+ entry.hashcodeFunction = NULL;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = NULL;
+
+ systemClasses[PKIX_MUTEX_TYPE] = entry;
+
+ PKIX_RETURN(MUTEX);
+}
+
+/* --Public-Functions--------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_Mutex_Create (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Mutex_Create(
+ PKIX_PL_Mutex **pNewLock,
+ void *plContext)
+{
+ PKIX_PL_Mutex *mutex = NULL;
+
+ PKIX_ENTER(MUTEX, "PKIX_PL_Mutex_Create");
+ PKIX_NULLCHECK_ONE(pNewLock);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_MUTEX_TYPE,
+ sizeof (PKIX_PL_Mutex),
+ (PKIX_PL_Object **)&mutex,
+ plContext),
+ PKIX_COULDNOTCREATELOCKOBJECT);
+
+ PKIX_MUTEX_DEBUG("\tCalling PR_NewLock).\n");
+ mutex->lock = PR_NewLock();
+
+ /* If an error occurred in NSPR, report it here */
+ if (mutex->lock == NULL) {
+ PKIX_DECREF(mutex);
+ PKIX_ERROR_ALLOC_ERROR();
+ }
+
+ *pNewLock = mutex;
+
+cleanup:
+
+ PKIX_RETURN(MUTEX);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Mutex_Lock (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Mutex_Lock(
+ PKIX_PL_Mutex *mutex,
+ void *plContext)
+{
+ PKIX_ENTER(MUTEX, "PKIX_PL_Mutex_Lock");
+ PKIX_NULLCHECK_ONE(mutex);
+
+ PKIX_MUTEX_DEBUG("\tCalling PR_Lock).\n");
+ PR_Lock(mutex->lock);
+
+ PKIX_MUTEX_DEBUG_ARG("(Thread %u just acquired the lock)\n",
+ (PKIX_UInt32)PR_GetCurrentThread());
+
+ PKIX_RETURN(MUTEX);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Mutex_Unlock (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Mutex_Unlock(
+ PKIX_PL_Mutex *mutex,
+ void *plContext)
+{
+ PRStatus result;
+
+ PKIX_ENTER(MUTEX, "PKIX_PL_Mutex_Unlock");
+ PKIX_NULLCHECK_ONE(mutex);
+
+ PKIX_MUTEX_DEBUG("\tCalling PR_Unlock).\n");
+ result = PR_Unlock(mutex->lock);
+
+ PKIX_MUTEX_DEBUG_ARG("(Thread %u just released the lock)\n",
+ (PKIX_UInt32)PR_GetCurrentThread());
+
+ if (result == PR_FAILURE) {
+ PKIX_ERROR_FATAL(PKIX_ERRORUNLOCKINGMUTEX);
+ }
+
+cleanup:
+ PKIX_RETURN(MUTEX);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mutex.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mutex.h
new file mode 100755
index 000000000..baf16fea9
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_mutex.h
@@ -0,0 +1,33 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_mutex.h
+ *
+ * Mutual Exclusion (Lock) Object Type Definition
+ *
+ */
+
+#ifndef _PKIX_PL_MUTEX_H
+#define _PKIX_PL_MUTEX_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_MutexStruct {
+ PRLock* lock;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_pl_Mutex_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_MUTEX_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.c
new file mode 100755
index 000000000..7dafa0b20
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.c
@@ -0,0 +1,1440 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_object.c
+ *
+ * Object Construction, Destruction and Callback Functions
+ *
+ */
+
+#include "pkix_pl_object.h"
+
+#ifdef PKIX_USER_OBJECT_TYPE
+/* --Class-Table-Initializers------------------------------------ */
+
+/*
+ * Create storage space for 20 Class Table buckets.
+ * These are only for user-defined types. System types are registered
+ * separately by PKIX_PL_Initialize.
+ */
+
+static pkix_pl_HT_Elem*
+pkix_Raw_ClassTable_Buckets[] = {
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
+};
+
+/*
+ * Allocate static memory for a ClassTable.
+ * XXX This assumes the bucket pointer will fit into a PKIX_UInt32
+ */
+static pkix_pl_PrimHashTable pkix_Raw_ClassTable = {
+ (void *)pkix_Raw_ClassTable_Buckets, /* Buckets */
+ 20 /* Number of Buckets */
+};
+static pkix_pl_PrimHashTable * classTable = &pkix_Raw_ClassTable;
+#endif /* PKIX_USER_OBJECT_TYPE */
+
+/* --Private-Functions-------------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_Object_GetHeader
+ * DESCRIPTION:
+ *
+ * Shifts Object pointed to by "object" by the sizeof(PKIX_PL_Object) and
+ * stores the value at "pObjectHeader".
+ *
+ * PARAMETERS:
+ * "object"
+ * Address of Object to shift. Must be non-NULL.
+ * "pObjectHeader"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Object_GetHeader(
+ PKIX_PL_Object *object,
+ PKIX_PL_Object **pObjectHeader,
+ void *plContext)
+{
+ PKIX_PL_Object *header = NULL;
+ PKIX_UInt32 objType;
+
+ PKIX_ENTER(OBJECT, "pkix_pl_Object_GetHeader");
+ PKIX_NULLCHECK_TWO(object, pObjectHeader);
+
+ PKIX_OBJECT_DEBUG("\tShifting object pointer).\n");
+
+ /* The header is sizeof(PKIX_PL_Object) before the object pointer */
+ header = (PKIX_PL_Object *)((char *)object - sizeof(PKIX_PL_Object));
+
+ objType = header->type;
+
+ if (objType >= PKIX_NUMTYPES) { /* if this is a user-defined type */
+#ifdef PKIX_USER_OBJECT_TYPE
+ pkix_ClassTable_Entry *ctEntry = NULL;
+
+ PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
+ PR_Lock(classTableLock);
+
+ PKIX_CHECK(pkix_pl_PrimHashTable_Lookup
+ (classTable,
+ (void *)&objType,
+ objType,
+ NULL,
+ (void **)&ctEntry,
+ plContext),
+ PKIX_ERRORGETTINGCLASSTABLEENTRY);
+
+ PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
+ PR_Unlock(classTableLock);
+
+ if (ctEntry == NULL) {
+ PKIX_ERROR_FATAL(PKIX_UNKNOWNOBJECTTYPE);
+ }
+#else
+ PORT_Assert(objType < PKIX_NUMTYPES);
+ pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
+ pkixErrorClass = PKIX_FATAL_ERROR;
+ goto cleanup;
+#endif /* PKIX_USER_OBJECT_TYPE */
+ }
+
+#ifdef PKIX_OBJECT_LEAK_TEST
+ PORT_Assert(header && header->magicHeader == PKIX_MAGIC_HEADER);
+#endif /* PKIX_OBJECT_LEAK_TEST */
+
+ if ((header == NULL)||
+ (header->magicHeader != PKIX_MAGIC_HEADER)) {
+ PKIX_ERROR_ALLOC_ERROR();
+ }
+
+ *pObjectHeader = header;
+
+cleanup:
+
+ PKIX_RETURN(OBJECT);
+}
+
+/*
+ * FUNCTION: pkix_Destroy_Object
+ * DESCRIPTION:
+ *
+ * Destroys and deallocates Object pointed to by "object". The caller is
+ * assumed to hold the Object's lock, which is acquired in
+ * PKIX_PL_Object_DecRef().
+ *
+ * PARAMETERS:
+ * "object"
+ * Address of Object to destroy. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Object_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_Object *objectHeader = NULL;
+
+ PKIX_ENTER(OBJECT, "pkix_pl_Object_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+#ifdef PKIX_OBJECT_LEAK_TEST
+ PKIX_CHECK_FATAL(pkix_pl_Object_GetHeader(object, &objectHeader, plContext),
+ PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
+#else
+ PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext),
+ PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
+#endif /* PKIX_OBJECT_LEAK_TEST */
+
+ /* Attempt to delete an object still being used */
+ if (objectHeader->references != 0) {
+ PKIX_ERROR_FATAL(PKIX_OBJECTSTILLREFERENCED);
+ }
+
+ PKIX_DECREF(objectHeader->stringRep);
+
+ /* Destroy this object's lock */
+ PKIX_OBJECT_DEBUG("\tCalling PR_DestroyLock).\n");
+ PR_DestroyLock(objectHeader->lock);
+ objectHeader->lock = NULL;
+ object = NULL;
+
+ objectHeader->magicHeader = PKIX_MAGIC_HEADER_DESTROYED;
+
+#ifdef PKIX_OBJECT_LEAK_TEST
+ memset(objectHeader, 0xbf, systemClasses[PKIX_OBJECT_TYPE].typeObjectSize);
+#endif
+
+ PKIX_FREE(objectHeader);
+
+cleanup:
+#ifdef PKIX_OBJECT_LEAK_TEST
+fatal:
+#endif
+
+ PKIX_RETURN(OBJECT);
+}
+
+/* --Default-Callbacks-------------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_Object_Equals_Default
+ * DESCRIPTION:
+ *
+ * Default Object_Equals callback: Compares the address of the Object pointed
+ * to by "firstObject" with the address of the Object pointed to by
+ * "secondObject" and stores the Boolean result at "pResult".
+ *
+ * PARAMETERS:
+ * "firstObject"
+ * Address of first Object to compare. Must be non-NULL.
+ * "secondObject"
+ * Address of second Object to compare. Must be non-NULL.
+ * "pResult"
+ * Address where Boolean result will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Object_Equals_Default(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_ENTER(OBJECT, "pkix_pl_Object_Equals_Default");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ /* Just compare pointer values */
+ *pResult = (firstObject == secondObject)?PKIX_TRUE:PKIX_FALSE;
+
+ PKIX_RETURN(OBJECT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Object_ToString_Default
+ * DESCRIPTION:
+ *
+ * Default Object_ToString callback: Creates a string consisting of the
+ * typename and address of the Object pointed to by "object" and stores
+ * the result at "pString". The format for the string is
+ * "TypeName@Address: <address>", where the default typename is "Object".
+ *
+ * PARAMETERS:
+ * "object"
+ * Address of Object to convert to a string. Must be non-NULL.
+ * "pString"
+ * Address where object pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an Object Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Object_ToString_Default(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_String *formatString = NULL;
+ PKIX_PL_String *descString = NULL;
+ char *format = "%s@Address: %x";
+ char *description = NULL;
+ PKIX_UInt32 objType;
+
+ PKIX_ENTER(OBJECT, "pkix_pl_Object_ToString_Default");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(PKIX_PL_Object_GetType(object, &objType, plContext),
+ PKIX_OBJECTGETTYPEFAILED);
+
+ if (objType >= PKIX_NUMTYPES){
+#ifdef PKIX_USER_OBJECT_TYPE
+ pkix_ClassTable_Entry *ctEntry = NULL;
+
+ PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
+ PR_Lock(classTableLock);
+ pkixErrorResult = pkix_pl_PrimHashTable_Lookup
+ (classTable,
+ (void *)&objType,
+ objType,
+ NULL,
+ (void **)&ctEntry,
+ plContext);
+ PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
+ PR_Unlock(classTableLock);
+ if (pkixErrorResult){
+ PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY);
+ }
+
+ if (ctEntry == NULL){
+ PKIX_ERROR_FATAL(PKIX_UNDEFINEDCLASSTABLEENTRY);
+ } else {
+ description = ctEntry->description;
+ if (description == NULL) {
+ description = "User Type Object";
+ }
+ }
+#else
+ PORT_Assert (0);
+ pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
+ pkixErrorClass = PKIX_FATAL_ERROR;
+ goto cleanup;
+#endif /* PKIX_USER_OBJECT_TYPE */
+ } else {
+ description = systemClasses[objType].description;
+ }
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII,
+ (void *)format,
+ 0,
+ &formatString,
+ plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII,
+ (void *)description,
+ 0,
+ &descString,
+ plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ PKIX_CHECK(PKIX_PL_Sprintf
+ (pString,
+ plContext,
+ formatString,
+ descString,
+ object),
+ PKIX_SPRINTFFAILED);
+
+cleanup:
+
+ PKIX_DECREF(formatString);
+ PKIX_DECREF(descString);
+
+ PKIX_RETURN(OBJECT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Object_Hashcode_Default
+ * DESCRIPTION:
+ *
+ * Default Object_Hashcode callback. Creates the a hashcode value using the
+ * address of the Object pointed to by "object" and stores the result at
+ * "pValue".
+ *
+ * XXX This isn't great since addresses are not uniformly distributed.
+ *
+ * PARAMETERS:
+ * "object"
+ * Address of Object to compute hashcode for. Must be non-NULL.
+ * "pValue"
+ * Address where PKIX_UInt32 will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_Object_Hashcode_Default(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pValue,
+ void *plContext)
+{
+ PKIX_ENTER(OBJECT, "pkix_pl_Object_Hashcode_Default");
+ PKIX_NULLCHECK_TWO(object, pValue);
+
+ *pValue = (PKIX_UInt32)((char *)object - (char *)NULL);
+
+ PKIX_RETURN(OBJECT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Object_RetrieveEqualsCallback
+ * DESCRIPTION:
+ *
+ * Retrieves Equals callback function of Object pointed to by "object and
+ * stores it at "pEqualsCallback". If the object's type is one of the system
+ * types, its callback function is retrieved from the systemClasses array;
+ * otherwise, its callback function is retrieve from the classTable hash
+ * table where user-defined types are stored.
+ *
+ * PARAMETERS:
+ * "object"
+ * Address of Object whose equals callback is desired. Must be non-NULL.
+ * "pEqualsCallback"
+ * Address where EqualsCallback function pointer will be stored.
+ * Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns an Object Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_Object_RetrieveEqualsCallback(
+ PKIX_PL_Object *object,
+ PKIX_PL_EqualsCallback *pEqualsCallback,
+ void *plContext)
+{
+ PKIX_PL_Object *objectHeader = NULL;
+ PKIX_PL_EqualsCallback func = NULL;
+ pkix_ClassTable_Entry entry;
+ PKIX_UInt32 objType;
+
+ PKIX_ENTER(OBJECT, "pkix_pl_Object_RetrieveEqualsCallback");
+ PKIX_NULLCHECK_TWO(object, pEqualsCallback);
+
+ PKIX_CHECK(pkix_pl_Object_GetHeader
+ (object, &objectHeader, plContext),
+ PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
+
+ objType = objectHeader->type;
+
+ if (objType >= PKIX_NUMTYPES){
+#ifdef PKIX_USER_OBJECT_TYPE
+ pkix_ClassTable_Entry *ctEntry = NULL;
+
+ PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
+ PR_Lock(classTableLock);
+ pkixErrorResult = pkix_pl_PrimHashTable_Lookup
+ (classTable,
+ (void *)&objType,
+ objType,
+ NULL,
+ (void **)&ctEntry,
+ plContext);
+ PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
+ PR_Unlock(classTableLock);
+ if (pkixErrorResult){
+ PKIX_ERROR(PKIX_ERRORGETTINGCLASSTABLEENTRY);
+ }
+
+ if ((ctEntry == NULL) || (ctEntry->equalsFunction == NULL)) {
+ PKIX_ERROR(PKIX_UNDEFINEDEQUALSCALLBACK);
+ } else {
+ *pEqualsCallback = ctEntry->equalsFunction;
+ }
+#else
+ PORT_Assert (0);
+ pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
+ pkixErrorClass = PKIX_FATAL_ERROR;
+ goto cleanup;
+#endif /* PKIX_USER_OBJECT_TYPE */
+ } else {
+ entry = systemClasses[objType];
+ func = entry.equalsFunction;
+ if (func == NULL){
+ func = pkix_pl_Object_Equals_Default;
+ }
+ *pEqualsCallback = func;
+ }
+
+cleanup:
+
+ PKIX_RETURN(OBJECT);
+}
+
+/*
+ * FUNCTION: pkix_pl_Object_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_OBJECT_TYPE and its related functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ *
+ * PKIX_PL_Object should have all function pointes to be to NULL: they
+ * work as proxy function to a real objects.
+ *
+ */
+PKIX_Error *
+pkix_pl_Object_RegisterSelf(void *plContext)
+{
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(ERROR, "pkix_pl_Object_RegisterSelf");
+
+ entry.description = "Object";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_Object);
+ entry.destructor = NULL;
+ entry.equalsFunction = NULL;
+ entry.hashcodeFunction = NULL;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = NULL;
+
+ systemClasses[PKIX_OBJECT_TYPE] = entry;
+
+ PKIX_RETURN(ERROR);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_Object_Alloc (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Object_Alloc(
+ PKIX_TYPENUM objType,
+ PKIX_UInt32 size,
+ PKIX_PL_Object **pObject,
+ void *plContext)
+{
+ PKIX_PL_Object *object = NULL;
+ pkix_ClassTable_Entry *ctEntry = NULL;
+
+ PKIX_ENTER(OBJECT, "PKIX_PL_Object_Alloc");
+ PKIX_NULLCHECK_ONE(pObject);
+
+ /*
+ * We need to ensure that user-defined types have been registered.
+ * All system types have already been registered by PKIX_PL_Initialize.
+ */
+
+ if (objType >= PKIX_NUMTYPES) { /* i.e. if this is a user-defined type */
+#ifdef PKIX_USER_OBJECT_TYPE
+ PKIX_Boolean typeRegistered;
+ PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
+ PR_Lock(classTableLock);
+ pkixErrorResult = pkix_pl_PrimHashTable_Lookup
+ (classTable,
+ (void *)&objType,
+ objType,
+ NULL,
+ (void **)&ctEntry,
+ plContext);
+ PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
+ PR_Unlock(classTableLock);
+ if (pkixErrorResult){
+ PKIX_ERROR_FATAL(PKIX_COULDNOTLOOKUPINHASHTABLE);
+ }
+
+ typeRegistered = (ctEntry != NULL);
+
+ if (!typeRegistered) {
+ PKIX_ERROR_FATAL(PKIX_UNKNOWNTYPEARGUMENT);
+ }
+#else
+ PORT_Assert (0);
+ pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
+ pkixErrorClass = PKIX_FATAL_ERROR;
+ goto cleanup;
+#endif /* PKIX_USER_OBJECT_TYPE */
+ } else {
+ ctEntry = &systemClasses[objType];
+ }
+
+ PORT_Assert(size == ctEntry->typeObjectSize);
+
+ /* Allocate space for the object header and the requested size */
+#ifdef PKIX_OBJECT_LEAK_TEST
+ PKIX_CHECK(PKIX_PL_Calloc
+ (1,
+ ((PKIX_UInt32)sizeof (PKIX_PL_Object))+size,
+ (void **)&object,
+ plContext),
+ PKIX_MALLOCFAILED);
+#else
+ PKIX_CHECK(PKIX_PL_Malloc
+ (((PKIX_UInt32)sizeof (PKIX_PL_Object))+size,
+ (void **)&object,
+ plContext),
+ PKIX_MALLOCFAILED);
+#endif /* PKIX_OBJECT_LEAK_TEST */
+
+ /* Initialize all object fields */
+ object->magicHeader = PKIX_MAGIC_HEADER;
+ object->type = objType;
+ object->references = 1; /* Default to a single reference */
+ object->stringRep = NULL;
+ object->hashcode = 0;
+ object->hashcodeCached = 0;
+
+ /* Cannot use PKIX_PL_Mutex because it depends on Object */
+ /* Using NSPR Locks instead */
+ PKIX_OBJECT_DEBUG("\tCalling PR_NewLock).\n");
+ object->lock = PR_NewLock();
+ if (object->lock == NULL) {
+ PKIX_ERROR_ALLOC_ERROR();
+ }
+
+ PKIX_OBJECT_DEBUG("\tShifting object pointer).\n");
+
+
+ /* Return a pointer to the user data. Need to offset by object size */
+ *pObject = object + 1;
+ object = NULL;
+
+ /* Atomically increment object counter */
+ PR_ATOMIC_INCREMENT((PRInt32*)&ctEntry->objCounter);
+
+cleanup:
+
+ PKIX_FREE(object);
+
+ PKIX_RETURN(OBJECT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Object_IsTypeRegistered (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Object_IsTypeRegistered(
+ PKIX_UInt32 objType,
+ PKIX_Boolean *pBool,
+ void *plContext)
+{
+#ifdef PKIX_USER_OBJECT_TYPE
+ pkix_ClassTable_Entry *ctEntry = NULL;
+#endif
+
+ PKIX_ENTER(OBJECT, "PKIX_PL_Object_IsTypeRegistered");
+ PKIX_NULLCHECK_ONE(pBool);
+
+ /* first, we handle the system types */
+ if (objType < PKIX_NUMTYPES) {
+ *pBool = PKIX_TRUE;
+ goto cleanup;
+ }
+
+#ifndef PKIX_USER_OBJECT_TYPE
+ PORT_Assert (0);
+ pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
+ pkixErrorClass = PKIX_FATAL_ERROR;
+#else
+ PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
+ PR_Lock(classTableLock);
+ pkixErrorResult = pkix_pl_PrimHashTable_Lookup
+ (classTable,
+ (void *)&objType,
+ objType,
+ NULL,
+ (void **)&ctEntry,
+ plContext);
+ PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
+ PR_Unlock(classTableLock);
+
+ if (pkixErrorResult){
+ PKIX_ERROR_FATAL(PKIX_COULDNOTLOOKUPINHASHTABLE);
+ }
+
+ *pBool = (ctEntry != NULL);
+#endif /* PKIX_USER_OBJECT_TYPE */
+
+cleanup:
+
+ PKIX_RETURN(OBJECT);
+}
+
+#ifdef PKIX_USER_OBJECT_TYPE
+/*
+ * FUNCTION: PKIX_PL_Object_RegisterType (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Object_RegisterType(
+ PKIX_UInt32 objType,
+ char *description,
+ PKIX_PL_DestructorCallback destructor,
+ PKIX_PL_EqualsCallback equalsFunction,
+ PKIX_PL_HashcodeCallback hashcodeFunction,
+ PKIX_PL_ToStringCallback toStringFunction,
+ PKIX_PL_ComparatorCallback comparator,
+ PKIX_PL_DuplicateCallback duplicateFunction,
+ void *plContext)
+{
+ pkix_ClassTable_Entry *ctEntry = NULL;
+ pkix_pl_Integer *key = NULL;
+
+ PKIX_ENTER(OBJECT, "PKIX_PL_Object_RegisterType");
+
+ /*
+ * System types are registered on startup by PKIX_PL_Initialize.
+ * These can not be overwritten.
+ */
+
+ if (objType < PKIX_NUMTYPES) { /* if this is a system type */
+ PKIX_ERROR(PKIX_CANTREREGISTERSYSTEMTYPE);
+ }
+
+ PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
+ PR_Lock(classTableLock);
+ PKIX_CHECK(pkix_pl_PrimHashTable_Lookup
+ (classTable,
+ (void *)&objType,
+ objType,
+ NULL,
+ (void **)&ctEntry,
+ plContext),
+ PKIX_PRIMHASHTABLELOOKUPFAILED);
+
+ /* If the type is already registered, throw an error */
+ if (ctEntry) {
+ PKIX_ERROR(PKIX_TYPEALREADYREGISTERED);
+ }
+
+ PKIX_CHECK(PKIX_PL_Malloc
+ (((PKIX_UInt32)sizeof (pkix_ClassTable_Entry)),
+ (void **)&ctEntry,
+ plContext),
+ PKIX_MALLOCFAILED);
+
+ /* Set Default Values if none specified */
+
+ if (description == NULL){
+ description = "Object";
+ }
+
+ if (equalsFunction == NULL) {
+ equalsFunction = pkix_pl_Object_Equals_Default;
+ }
+
+ if (toStringFunction == NULL) {
+ toStringFunction = pkix_pl_Object_ToString_Default;
+ }
+
+ if (hashcodeFunction == NULL) {
+ hashcodeFunction = pkix_pl_Object_Hashcode_Default;
+ }
+
+ ctEntry->destructor = destructor;
+ ctEntry->equalsFunction = equalsFunction;
+ ctEntry->toStringFunction = toStringFunction;
+ ctEntry->hashcodeFunction = hashcodeFunction;
+ ctEntry->comparator = comparator;
+ ctEntry->duplicateFunction = duplicateFunction;
+ ctEntry->description = description;
+
+ PKIX_CHECK(PKIX_PL_Malloc
+ (((PKIX_UInt32)sizeof (pkix_pl_Integer)),
+ (void **)&key,
+ plContext),
+ PKIX_COULDNOTMALLOCNEWKEY);
+
+ key->ht_int = objType;
+
+ PKIX_CHECK(pkix_pl_PrimHashTable_Add
+ (classTable,
+ (void *)key,
+ (void *)ctEntry,
+ objType,
+ NULL,
+ plContext),
+ PKIX_PRIMHASHTABLEADDFAILED);
+
+cleanup:
+ PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
+ PR_Unlock(classTableLock);
+
+ PKIX_RETURN(OBJECT);
+}
+#endif /* PKIX_USER_OBJECT_TYPE */
+
+/*
+ * FUNCTION: PKIX_PL_Object_IncRef (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Object_IncRef(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_Object *objectHeader = NULL;
+ PKIX_PL_NssContext *context = NULL;
+ PKIX_Int32 refCount = 0;
+
+ PKIX_ENTER(OBJECT, "PKIX_PL_Object_IncRef");
+ PKIX_NULLCHECK_ONE(object);
+
+ if (plContext){
+ /*
+ * PKIX_PL_NssContext is not a complete PKIX Type, it doesn't
+ * have a header therefore we cannot verify its type before
+ * casting.
+ */
+ context = (PKIX_PL_NssContext *) plContext;
+ if (context->arena != NULL) {
+ goto cleanup;
+ }
+ }
+
+ if (object == (PKIX_PL_Object*)PKIX_ALLOC_ERROR()) {
+ goto cleanup;
+ }
+
+ /* Shift pointer from user data to object header */
+ PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext),
+ PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
+
+ /* This object should never have zero references */
+ refCount = PR_ATOMIC_INCREMENT(&objectHeader->references);
+
+ if (refCount <= 1) {
+ PKIX_THROW(FATAL, PKIX_OBJECTWITHNONPOSITIVEREFERENCES);
+ }
+
+cleanup:
+
+ PKIX_RETURN(OBJECT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Object_DecRef (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Object_DecRef(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_Int32 refCount = 0;
+ PKIX_PL_Object *objectHeader = NULL;
+ PKIX_PL_NssContext *context = NULL;
+
+ PKIX_ENTER(OBJECT, "PKIX_PL_Object_DecRef");
+ PKIX_NULLCHECK_ONE(object);
+
+ if (plContext){
+ /*
+ * PKIX_PL_NssContext is not a complete PKIX Type, it doesn't
+ * have a header therefore we cannot verify its type before
+ * casting.
+ */
+ context = (PKIX_PL_NssContext *) plContext;
+ if (context->arena != NULL) {
+ goto cleanup;
+ }
+ }
+
+ if (object == (PKIX_PL_Object*)PKIX_ALLOC_ERROR()) {
+ goto cleanup;
+ }
+
+ /* Shift pointer from user data to object header */
+ PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext),
+ PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
+
+ refCount = PR_ATOMIC_DECREMENT(&objectHeader->references);
+
+ if (refCount == 0) {
+ PKIX_PL_DestructorCallback destructor = NULL;
+ pkix_ClassTable_Entry *ctEntry = NULL;
+ PKIX_UInt32 objType = objectHeader->type;
+
+ /* first, special handling for system types */
+ if (objType >= PKIX_NUMTYPES){
+#ifdef PKIX_USER_OBJECT_TYPE
+ PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
+ PR_Lock(classTableLock);
+ pkixErrorResult = pkix_pl_PrimHashTable_Lookup
+ (classTable,
+ (void *)&objType,
+ objType,
+ NULL,
+ (void **)&ctEntry,
+ plContext);
+ PKIX_OBJECT_DEBUG
+ ("\tCalling PR_Unlock).\n");
+ PR_Unlock(classTableLock);
+ if (pkixErrorResult){
+ PKIX_ERROR_FATAL
+ (PKIX_ERRORINGETTINGDESTRUCTOR);
+ }
+
+ if (ctEntry != NULL){
+ destructor = ctEntry->destructor;
+ }
+#else
+ PORT_Assert (0);
+ pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
+ pkixErrorClass = PKIX_FATAL_ERROR;
+ goto cleanup;
+#endif /* PKIX_USER_OBJECT_TYPE */
+ } else {
+ ctEntry = &systemClasses[objType];
+ destructor = ctEntry->destructor;
+ }
+
+ if (destructor != NULL){
+ /* Call destructor on user data if necessary */
+ pkixErrorResult = destructor(object, plContext);
+ if (pkixErrorResult) {
+ pkixErrorClass = PKIX_FATAL_ERROR;
+ PKIX_DoAddError(stdVarsPtr, pkixErrorResult, plContext);
+ pkixErrorResult = NULL;
+ }
+ }
+
+ /* Atomically decrement object counter */
+ PR_ATOMIC_DECREMENT((PRInt32*)&ctEntry->objCounter);
+
+ /* pkix_pl_Object_Destroy assumes the lock is held */
+ /* It will call unlock and destroy the object */
+ pkixErrorResult = pkix_pl_Object_Destroy(object, plContext);
+ goto cleanup;
+ }
+
+ if (refCount < 0) {
+ PKIX_ERROR_ALLOC_ERROR();
+ }
+
+cleanup:
+
+ PKIX_RETURN(OBJECT);
+}
+
+
+
+/*
+ * FUNCTION: PKIX_PL_Object_Equals (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Object_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_PL_Object *firstObjectHeader = NULL;
+ PKIX_PL_Object *secondObjectHeader = NULL;
+ PKIX_PL_EqualsCallback func = NULL;
+ pkix_ClassTable_Entry entry;
+ PKIX_UInt32 objType;
+
+ PKIX_ENTER(OBJECT, "PKIX_PL_Object_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ PKIX_CHECK(pkix_pl_Object_GetHeader
+ (firstObject, &firstObjectHeader, plContext),
+ PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
+
+ PKIX_CHECK(pkix_pl_Object_GetHeader
+ (secondObject, &secondObjectHeader, plContext),
+ PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
+
+ /* if hashcodes are cached but not equal, objects can't be equal */
+ if (firstObjectHeader->hashcodeCached &&
+ secondObjectHeader->hashcodeCached){
+ if (firstObjectHeader->hashcode !=
+ secondObjectHeader->hashcode){
+ *pResult = PKIX_FALSE;
+ goto cleanup;
+ }
+ }
+
+ objType = firstObjectHeader->type;
+
+ if (objType >= PKIX_NUMTYPES) {
+#ifdef PKIX_USER_OBJECT_TYPE
+ pkix_ClassTable_Entry *ctEntry = NULL;
+ PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
+ PR_Lock(classTableLock);
+ pkixErrorResult = pkix_pl_PrimHashTable_Lookup
+ (classTable,
+ (void *)&firstObjectHeader->type,
+ firstObjectHeader->type,
+ NULL,
+ (void **)&ctEntry,
+ plContext);
+ PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
+ PR_Unlock(classTableLock);
+
+ if (pkixErrorResult){
+ PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY);
+ }
+
+ if ((ctEntry == NULL) || (ctEntry->equalsFunction == NULL)) {
+ PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK);
+ } else {
+ func = ctEntry->equalsFunction;
+ }
+#else
+ PORT_Assert (0);
+ pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
+ pkixErrorClass = PKIX_FATAL_ERROR;
+ goto cleanup;
+#endif /* PKIX_USER_OBJECT_TYPE */
+ } else {
+ entry = systemClasses[objType];
+ func = entry.equalsFunction;
+ if (func == NULL){
+ func = pkix_pl_Object_Equals_Default;
+ }
+ }
+
+ PKIX_CHECK(func(firstObject, secondObject, pResult, plContext),
+ PKIX_OBJECTSPECIFICFUNCTIONFAILED);
+
+cleanup:
+
+ PKIX_RETURN(OBJECT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Object_Duplicate (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Object_Duplicate(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object **pNewObject,
+ void *plContext)
+{
+ PKIX_PL_Object *firstObjectHeader = NULL;
+ PKIX_PL_DuplicateCallback func = NULL;
+ pkix_ClassTable_Entry entry;
+ PKIX_UInt32 objType;
+
+ PKIX_ENTER(OBJECT, "PKIX_PL_Object_Duplicate");
+ PKIX_NULLCHECK_TWO(firstObject, pNewObject);
+
+ PKIX_CHECK(pkix_pl_Object_GetHeader
+ (firstObject, &firstObjectHeader, plContext),
+ PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
+
+ objType = firstObjectHeader->type;
+
+ if (objType >= PKIX_NUMTYPES) {
+#ifdef PKIX_USER_OBJECT_TYPE
+ pkix_ClassTable_Entry *ctEntry = NULL;
+
+ PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
+ PR_Lock(classTableLock);
+ pkixErrorResult = pkix_pl_PrimHashTable_Lookup
+ (classTable,
+ (void *)&objType,
+ objType,
+ NULL,
+ (void **)&ctEntry,
+ plContext);
+ PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
+ PR_Unlock(classTableLock);
+
+ if (pkixErrorResult){
+ PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY);
+ }
+
+ if ((ctEntry == NULL) || (ctEntry->duplicateFunction == NULL)) {
+ PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK);
+ } else {
+ func = ctEntry->duplicateFunction;
+ }
+#else
+ PORT_Assert (0);
+ pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
+ pkixErrorClass = PKIX_FATAL_ERROR;
+ goto cleanup;
+#endif /* PKIX_USER_OBJECT_TYPE */
+ } else {
+ entry = systemClasses[objType];
+ func = entry.duplicateFunction;
+ if (!func){
+ PKIX_ERROR_FATAL(PKIX_UNDEFINEDDUPLICATEFUNCTION);
+ }
+ }
+
+ PKIX_CHECK(func(firstObject, pNewObject, plContext),
+ PKIX_OBJECTSPECIFICFUNCTIONFAILED);
+
+cleanup:
+
+ PKIX_RETURN(OBJECT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Object_Hashcode (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Object_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pValue,
+ void *plContext)
+{
+ PKIX_PL_Object *objectHeader = NULL;
+ PKIX_PL_HashcodeCallback func = NULL;
+ pkix_ClassTable_Entry entry;
+ PKIX_UInt32 objectHash;
+
+ PKIX_ENTER(OBJECT, "PKIX_PL_Object_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pValue);
+
+ /* Shift pointer from user data to object header */
+ PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext),
+ PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
+
+ /* if we don't have a cached copy from before, we create one */
+ if (!objectHeader->hashcodeCached){
+
+ PKIX_UInt32 objType = objectHeader->type;
+
+ /* first, special handling for system types */
+ if (objType >= PKIX_NUMTYPES){
+#ifdef PKIX_USER_OBJECT_TYPE
+ pkix_ClassTable_Entry *ctEntry = NULL;
+
+ PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
+ PR_Lock(classTableLock);
+ pkixErrorResult = pkix_pl_PrimHashTable_Lookup
+ (classTable,
+ (void *)&objType,
+ objType,
+ NULL,
+ (void **)&ctEntry,
+ plContext);
+ PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
+ PR_Unlock(classTableLock);
+
+ if (pkixErrorResult){
+ PKIX_ERROR_FATAL
+ (PKIX_ERRORGETTINGCLASSTABLEENTRY);
+ }
+
+ if ((ctEntry == NULL) ||
+ (ctEntry->hashcodeFunction == NULL)) {
+ PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK);
+ }
+
+ func = ctEntry->hashcodeFunction;
+#else
+ PORT_Assert (0);
+ pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
+ pkixErrorClass = PKIX_FATAL_ERROR;
+ goto cleanup;
+#endif /* PKIX_USER_OBJECT_TYPE */
+ } else {
+ entry = systemClasses[objType];
+ func = entry.hashcodeFunction;
+ if (func == NULL){
+ func = pkix_pl_Object_Hashcode_Default;
+ }
+ }
+
+ PKIX_CHECK(func(object, &objectHash, plContext),
+ PKIX_OBJECTSPECIFICFUNCTIONFAILED);
+
+ if (!objectHeader->hashcodeCached){
+
+ PKIX_CHECK(pkix_LockObject(object, plContext),
+ PKIX_ERRORLOCKINGOBJECT);
+
+ if (!objectHeader->hashcodeCached){
+ /* save cached copy in case we need it again */
+ objectHeader->hashcode = objectHash;
+ objectHeader->hashcodeCached = PKIX_TRUE;
+ }
+
+ PKIX_CHECK(pkix_UnlockObject(object, plContext),
+ PKIX_ERRORUNLOCKINGOBJECT);
+ }
+ }
+
+ *pValue = objectHeader->hashcode;
+
+cleanup:
+
+ PKIX_RETURN(OBJECT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Object_ToString (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Object_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_Object *objectHeader = NULL;
+ PKIX_PL_ToStringCallback func = NULL;
+ pkix_ClassTable_Entry entry;
+ PKIX_PL_String *objectString = NULL;
+
+ PKIX_ENTER(OBJECT, "PKIX_PL_Object_ToString");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ /* Shift pointer from user data to object header */
+ PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext),
+ PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
+
+ /* if we don't have a cached copy from before, we create one */
+ if (!objectHeader->stringRep){
+
+ PKIX_UInt32 objType = objectHeader->type;
+
+ if (objType >= PKIX_NUMTYPES){
+#ifdef PKIX_USER_OBJECT_TYPE
+ pkix_ClassTable_Entry *ctEntry = NULL;
+
+ PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
+ PR_Lock(classTableLock);
+ pkixErrorResult = pkix_pl_PrimHashTable_Lookup
+ (classTable,
+ (void *)&objType,
+ objType,
+ NULL,
+ (void **)&ctEntry,
+ plContext);
+ PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
+ PR_Unlock(classTableLock);
+ if (pkixErrorResult){
+ PKIX_ERROR_FATAL
+ (PKIX_ERRORGETTINGCLASSTABLEENTRY);
+ }
+
+ if ((ctEntry == NULL) ||
+ (ctEntry->toStringFunction == NULL)) {
+ PKIX_ERROR_FATAL(PKIX_UNDEFINEDCALLBACK);
+ }
+
+ func = ctEntry->toStringFunction;
+#else
+ PORT_Assert (0);
+ pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
+ pkixErrorClass = PKIX_FATAL_ERROR;
+ goto cleanup;
+#endif /* PKIX_USER_OBJECT_TYPE */
+ } else {
+ entry = systemClasses[objType];
+ func = entry.toStringFunction;
+ if (func == NULL){
+ func = pkix_pl_Object_ToString_Default;
+ }
+ }
+
+ PKIX_CHECK(func(object, &objectString, plContext),
+ PKIX_OBJECTSPECIFICFUNCTIONFAILED);
+
+ if (!objectHeader->stringRep){
+
+ PKIX_CHECK(pkix_LockObject(object, plContext),
+ PKIX_ERRORLOCKINGOBJECT);
+
+ if (!objectHeader->stringRep){
+ /* save a cached copy */
+ objectHeader->stringRep = objectString;
+ objectString = NULL;
+ }
+
+ PKIX_CHECK(pkix_UnlockObject(object, plContext),
+ PKIX_ERRORUNLOCKINGOBJECT);
+ }
+ }
+
+
+ *pString = objectHeader->stringRep;
+ objectHeader->stringRep = NULL;
+
+cleanup:
+ if (objectHeader) {
+ PKIX_DECREF(objectHeader->stringRep);
+ }
+ PKIX_DECREF(objectString);
+
+ PKIX_RETURN(OBJECT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Object_InvalidateCache (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Object_InvalidateCache(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_Object *objectHeader = NULL;
+
+ PKIX_ENTER(OBJECT, "PKIX_PL_Object_InvalidateCache");
+ PKIX_NULLCHECK_ONE(object);
+
+ /* Shift pointer from user data to object header */
+ PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext),
+ PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
+
+ PKIX_CHECK(pkix_LockObject(object, plContext),
+ PKIX_ERRORLOCKINGOBJECT);
+
+ /* invalidate hashcode */
+ objectHeader->hashcode = 0;
+ objectHeader->hashcodeCached = PKIX_FALSE;
+
+ PKIX_DECREF(objectHeader->stringRep);
+
+ PKIX_CHECK(pkix_UnlockObject(object, plContext),
+ PKIX_ERRORUNLOCKINGOBJECT);
+
+cleanup:
+
+ PKIX_RETURN(OBJECT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Object_Compare (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Object_Compare(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Int32 *pResult,
+ void *plContext)
+{
+ PKIX_PL_Object *firstObjectHeader = NULL;
+ PKIX_PL_Object *secondObjectHeader = NULL;
+ PKIX_PL_ComparatorCallback func = NULL;
+ pkix_ClassTable_Entry entry;
+ PKIX_UInt32 objType;
+
+ PKIX_ENTER(OBJECT, "PKIX_PL_Object_Compare");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ /* Shift pointer from user data to object header */
+ PKIX_CHECK(pkix_pl_Object_GetHeader
+ (firstObject, &firstObjectHeader, plContext),
+ PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
+
+ /* Shift pointer from user data to object header */
+ PKIX_CHECK(pkix_pl_Object_GetHeader
+ (secondObject, &secondObjectHeader, plContext),
+ PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
+
+ objType = firstObjectHeader->type;
+
+ if (objType >= PKIX_NUMTYPES){
+#ifdef PKIX_USER_OBJECT_TYPE
+ pkix_ClassTable_Entry *ctEntry = NULL;
+
+ PKIX_OBJECT_DEBUG("\tCalling PR_Lock).\n");
+ PR_Lock(classTableLock);
+ pkixErrorResult = pkix_pl_PrimHashTable_Lookup
+ (classTable,
+ (void *)&objType,
+ objType,
+ NULL,
+ (void **)&ctEntry,
+ plContext);
+ PKIX_OBJECT_DEBUG("\tCalling PR_Unlock).\n");
+ PR_Unlock(classTableLock);
+ if (pkixErrorResult){
+ PKIX_ERROR_FATAL(PKIX_ERRORGETTINGCLASSTABLEENTRY);
+ }
+
+ if ((ctEntry == NULL) || (ctEntry->comparator == NULL)) {
+ PKIX_ERROR_FATAL(PKIX_UNDEFINEDCOMPARATOR);
+ }
+
+ func = ctEntry->comparator;
+#else
+ PORT_Assert (0);
+ pkixErrorCode = PKIX_UNKNOWNOBJECTTYPE;
+ pkixErrorClass = PKIX_FATAL_ERROR;
+ goto cleanup;
+#endif /* PKIX_USER_OBJECT_TYPE */
+ } else {
+ /* special handling for system types */
+ entry = systemClasses[objType];
+ func = entry.comparator;
+ if (!func){
+ PKIX_ERROR(PKIX_UNDEFINEDCOMPARATOR);
+ }
+ }
+
+ PKIX_CHECK(func(firstObject, secondObject, pResult, plContext),
+ PKIX_OBJECTSPECIFICFUNCTIONFAILED);
+
+cleanup:
+
+ PKIX_RETURN(OBJECT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Object_Lock (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Object_Lock(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_ENTER(OBJECT, "PKIX_PL_Object_Lock");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_LockObject(object, plContext),
+ PKIX_LOCKOBJECTFAILED);
+
+cleanup:
+
+ PKIX_RETURN(OBJECT);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Object_Unlock (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Object_Unlock(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_ENTER(OBJECT, "PKIX_PL_Object_Unlock");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_UnlockObject(object, plContext),
+ PKIX_UNLOCKOBJECTFAILED);
+
+cleanup:
+
+ PKIX_RETURN(OBJECT);
+}
+
+
+/*
+ * FUNCTION: PKIX_PL_Object_GetType (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Object_GetType(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pType,
+ void *plContext)
+{
+ PKIX_PL_Object *objectHeader = NULL;
+
+ PKIX_ENTER(OBJECT, "PKIX_PL_Object_GetType");
+ PKIX_NULLCHECK_TWO(object, pType);
+
+ /* Shift pointer from user data to object header */
+ PKIX_CHECK(pkix_pl_Object_GetHeader(object, &objectHeader, plContext),
+ PKIX_RECEIVEDCORRUPTEDOBJECTARGUMENT);
+
+ *pType = objectHeader->type;
+
+cleanup:
+
+ PKIX_RETURN(OBJECT);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.h
new file mode 100755
index 000000000..0133c43ee
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_object.h
@@ -0,0 +1,76 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_object.h
+ *
+ * Object Construction, Destruction and Callback Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_OBJECT_H
+#define _PKIX_PL_OBJECT_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Object Implementation Notes:
+ *
+ * Allocating a new object creates an object header and a block of
+ * uninitialized user data. A pointer to this uninitialized data is
+ * returned to the user. The structure looks as follows:
+ *
+ * +--------------------+
+ * | MAGIC HEADER |
+ * | (object header) |
+ * +--------------------+
+ * | user data | -- pointer returned from PKIX_PL_Object_Alloc
+ * +--------------------+
+ *
+ * Object operations receive a pointer to raw user data as an argument.
+ * The macro HEADER(object) returns a pointer to the object header.
+ * An assertion then verifies that the first field is the MAGIC_HEADER.
+ */
+
+/* PKIX_PL_Object Structure Definition */
+struct PKIX_PL_ObjectStruct {
+ PRUint64 magicHeader;
+ PKIX_UInt32 type;
+ PKIX_Int32 references;
+ PRLock *lock;
+ PKIX_PL_String *stringRep;
+ PKIX_UInt32 hashcode;
+ PKIX_Boolean hashcodeCached;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_pl_Object_RetrieveEqualsCallback(
+ PKIX_PL_Object *object,
+ PKIX_PL_EqualsCallback *equalsCallback,
+ void *plContext);
+
+extern PKIX_Boolean initializing;
+extern PKIX_Boolean initialized;
+
+#ifdef PKIX_USER_OBJECT_TYPE
+
+extern PRLock *classTableLock;
+
+#endif
+
+extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+
+PKIX_Error *
+pkix_pl_Object_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_OBJECT_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_oid.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_oid.c
new file mode 100755
index 000000000..a6e050385
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_oid.c
@@ -0,0 +1,316 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_oid.c
+ *
+ * OID Object Functions
+ *
+ */
+
+#include "pkix_pl_oid.h"
+
+/* --Private-OID-Functions---------------------------------------- */
+
+ /*
+ * FUNCTION: pkix_pl_OID_Comparator
+ * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_OID_Comparator(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Int32 *pRes,
+ void *plContext)
+{
+ PKIX_PL_OID *firstOID = NULL;
+ PKIX_PL_OID *secondOID = NULL;
+
+ PKIX_ENTER(OID, "pkix_pl_OID_Comparator");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pRes);
+
+ PKIX_CHECK(pkix_CheckTypes
+ (firstObject, secondObject, PKIX_OID_TYPE, plContext),
+ PKIX_ARGUMENTSNOTOIDS);
+
+ firstOID = (PKIX_PL_OID*)firstObject;
+ secondOID = (PKIX_PL_OID*)secondObject;
+
+ *pRes = (PKIX_Int32)SECITEM_CompareItem(&firstOID->derOid,
+ &secondOID->derOid);
+cleanup:
+ PKIX_RETURN(OID);
+}
+
+/*
+ * FUNCTION: pkix_pl_OID_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_OID_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_OID *oid = NULL;
+
+ PKIX_ENTER(OID, "pkix_pl_OID_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_OID_TYPE, plContext),
+ PKIX_OBJECTNOTANOID);
+ oid = (PKIX_PL_OID*)object;
+ SECITEM_FreeItem(&oid->derOid, PR_FALSE);
+
+cleanup:
+ PKIX_RETURN(OID);
+}
+
+/*
+ * FUNCTION: pkix_pl_OID_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_OID_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_OID *oid = NULL;
+
+ PKIX_ENTER(OID, "pkix_pl_OID_HashCode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_OID_TYPE, plContext),
+ PKIX_OBJECTNOTANOID);
+
+ oid = (PKIX_PL_OID *)object;
+
+ PKIX_CHECK(pkix_hash
+ ((unsigned char *)oid->derOid.data,
+ oid->derOid.len * sizeof (char),
+ pHashcode,
+ plContext),
+ PKIX_HASHFAILED);
+cleanup:
+
+ PKIX_RETURN(OID);
+}
+
+/*
+ * FUNCTION: pkix_pl_OID_Equals
+ * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_OID_Equals(
+ PKIX_PL_Object *first,
+ PKIX_PL_Object *second,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_Int32 cmpResult;
+
+ PKIX_ENTER(OID, "pkix_pl_OID_Equals");
+ PKIX_NULLCHECK_THREE(first, second, pResult);
+
+ PKIX_CHECK(pkix_pl_OID_Comparator
+ (first, second, &cmpResult, plContext),
+ PKIX_OIDCOMPARATORFAILED);
+
+ *pResult = (cmpResult == 0);
+cleanup:
+
+ PKIX_RETURN(OID);
+}
+
+/*
+ * FUNCTION: pkix_pl_OID_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ * Use this function only for printing OIDs and not to make any
+ * critical security decision.
+ */
+static PKIX_Error *
+pkix_pl_OID_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_OID *oid = NULL;
+ char *oidString = NULL;
+
+ PKIX_ENTER(OID, "pkix_pl_OID_toString");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_OID_TYPE, plContext),
+ PKIX_OBJECTNOTANOID);
+ oid = (PKIX_PL_OID*)object;
+ oidString = CERT_GetOidString(&oid->derOid);
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, oidString , 0, pString, plContext),
+ PKIX_STRINGCREATEFAILED);
+cleanup:
+ PR_smprintf_free(oidString);
+
+ PKIX_RETURN(OID);
+}
+
+/*
+ * FUNCTION: pkix_pl_OID_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_OID_TYPE and its related functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_OID_RegisterSelf(
+ void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry *entry = &systemClasses[PKIX_OID_TYPE];
+
+ PKIX_ENTER(OID, "pkix_pl_OID_RegisterSelf");
+
+ entry->description = "OID";
+ entry->typeObjectSize = sizeof(PKIX_PL_OID);
+ entry->destructor = pkix_pl_OID_Destroy;
+ entry->equalsFunction = pkix_pl_OID_Equals;
+ entry->hashcodeFunction = pkix_pl_OID_Hashcode;
+ entry->toStringFunction = pkix_pl_OID_ToString;
+ entry->comparator = pkix_pl_OID_Comparator;
+ entry->duplicateFunction = pkix_duplicateImmutable;
+
+ PKIX_RETURN(OID);
+}
+
+/*
+ * FUNCTION: pkix_pl_OID_GetCriticalExtensionOIDs
+ * DESCRIPTION:
+ *
+ * Converts the extensions in "extensions" array that are critical to
+ * PKIX_PL_OID and returns the result as a PKIX_List in "pPidList".
+ * If there is no critical extension, an empty list is returned.
+ *
+ * PARAMETERS
+ * "extension"
+ * an array of extension pointers. May be NULL.
+ * "pOidsList"
+ * Address where the list of OIDs is returned. Must be non-NULL.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a CRL Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_OID_GetCriticalExtensionOIDs(
+ CERTCertExtension **extensions,
+ PKIX_List **pOidsList,
+ void *plContext)
+{
+ PKIX_List *oidsList = NULL;
+ PKIX_PL_OID *pkixOID = NULL;
+
+ PKIX_ENTER(OID, "pkix_pl_OID_GetCriticalExtensionOIDs");
+ PKIX_NULLCHECK_ONE(pOidsList);
+
+ PKIX_CHECK(PKIX_List_Create(&oidsList, plContext),
+ PKIX_LISTCREATEFAILED);
+
+ if (extensions) {
+ while (*extensions) {
+ CERTCertExtension *extension = NULL;
+ SECItem *critical = NULL;
+ SECItem *oid = NULL;
+
+ extension = *extensions++;
+ /* extension is critical ? */
+ critical = &extension->critical;
+ if (critical->len == 0 || critical->data[0] == 0) {
+ continue;
+ }
+ oid = &extension->id;
+ PKIX_CHECK(
+ PKIX_PL_OID_CreateBySECItem(oid, &pkixOID, plContext),
+ PKIX_OIDCREATEFAILED);
+ PKIX_CHECK(
+ PKIX_List_AppendItem(oidsList, (PKIX_PL_Object *)pkixOID,
+ plContext),
+ PKIX_LISTAPPENDITEMFAILED);
+ PKIX_DECREF(pkixOID);
+ }
+ }
+
+ *pOidsList = oidsList;
+ oidsList = NULL;
+
+cleanup:
+ PKIX_DECREF(oidsList);
+ PKIX_DECREF(pkixOID);
+ PKIX_RETURN(OID);
+}
+
+/* --Public-Functions------------------------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_OID_CreateBySECItem (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_OID_CreateBySECItem(
+ SECItem *derOid,
+ PKIX_PL_OID **pOID,
+ void *plContext)
+{
+ PKIX_PL_OID *oid = NULL;
+ SECStatus rv;
+
+ PKIX_ENTER(OID, "PKIX_PL_OID_CreateBySECItem");
+ PKIX_NULLCHECK_TWO(pOID, derOid);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_OID_TYPE,
+ sizeof (PKIX_PL_OID),
+ (PKIX_PL_Object **)&oid,
+ plContext),
+ PKIX_COULDNOTCREATEOBJECT);
+ rv = SECITEM_CopyItem(NULL, &oid->derOid, derOid);
+ if (rv != SECSuccess) {
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+ *pOID = oid;
+ oid = NULL;
+
+cleanup:
+ PKIX_DECREF(oid);
+
+ PKIX_RETURN(OID);
+}
+
+/*
+ * FUNCTION: PKIX_PL_OID_Create (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_OID_Create(
+ SECOidTag idtag,
+ PKIX_PL_OID **pOID,
+ void *plContext)
+{
+ SECOidData *oidData = NULL;
+
+ PKIX_ENTER(OID, "PKIX_PL_OID_Create");
+ PKIX_NULLCHECK_ONE(pOID);
+
+ oidData = SECOID_FindOIDByTag((SECOidTag)idtag);
+ if (!oidData) {
+ PKIX_ERROR(PKIX_SECOIDFINDOIDTAGDESCRIPTIONFAILED);
+ }
+
+ pkixErrorResult =
+ PKIX_PL_OID_CreateBySECItem(&oidData->oid, pOID, plContext);
+cleanup:
+ PKIX_RETURN(OID);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_oid.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_oid.h
new file mode 100755
index 000000000..0229194d8
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_oid.h
@@ -0,0 +1,39 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_oid.h
+ *
+ * OID Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_OID_H
+#define _PKIX_PL_OID_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_OIDStruct {
+ SECItem derOid;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_pl_OID_RegisterSelf(void *plContext);
+
+PKIX_Error *
+pkix_pl_OID_GetCriticalExtensionOIDs(
+ CERTCertExtension **extensions,
+ PKIX_List **pOidsList,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_OID_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_primhash.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_primhash.c
new file mode 100755
index 000000000..c920533d3
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_primhash.c
@@ -0,0 +1,584 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_primhash.c
+ *
+ * Primitive (non-object) Hashtable Functions
+ *
+ */
+
+#include "pkix_pl_primhash.h"
+
+/* --Private-Functions---------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_KeyComparator_Default
+ * DESCRIPTION:
+ *
+ * Compares the integer pointed to by "firstKey" with the integer pointed to
+ * by "secondKey" for equality and stores the Boolean result at "pResult".
+ * This default key comparator assumes each key is a PKIX_UInt32, and it
+ * simply tests them for equality.
+ *
+ * PARAMETERS:
+ * "firstKey"
+ * Address of the first integer key to compare. Must be non-NULL.
+ * The EqualsCallback for this Object will be called.
+ * "secondKey"
+ * Address of the second integer key to compare. Must be non-NULL.
+ * "pResult"
+ * Address where Boolean will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+static PKIX_Error *
+pkix_pl_KeyComparator_Default(
+ PKIX_UInt32 *firstKey,
+ PKIX_UInt32 *secondKey,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ /* Assume both keys are pointers to PKIX_UInt32 */
+ PKIX_UInt32 firstInt, secondInt;
+
+ PKIX_ENTER(HASHTABLE, "pkix_pl_KeyComparator_Default");
+ PKIX_NULLCHECK_THREE(firstKey, secondKey, pResult);
+
+ firstInt = *firstKey;
+ secondInt = *secondKey;
+
+ *pResult = (firstInt == secondInt)?PKIX_TRUE:PKIX_FALSE;
+
+ PKIX_RETURN(HASHTABLE);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_PrimHashTable_Create
+ * DESCRIPTION:
+ *
+ * Creates a new PrimHashtable object with a number of buckets equal to
+ * "numBuckets" and stores the result at "pResult".
+ *
+ * PARAMETERS:
+ * "numBuckets"
+ * The number of hash table buckets. Must be non-zero.
+ * "pResult"
+ * Address where PrimHashTable pointer will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Thread Safe (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_PrimHashTable_Create(
+ PKIX_UInt32 numBuckets,
+ pkix_pl_PrimHashTable **pResult,
+ void *plContext)
+{
+ pkix_pl_PrimHashTable *primHashTable = NULL;
+ PKIX_UInt32 i;
+
+ PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Create");
+ PKIX_NULLCHECK_ONE(pResult);
+
+ if (numBuckets == 0) {
+ PKIX_ERROR(PKIX_NUMBUCKETSEQUALSZERO);
+ }
+
+ /* Allocate a new hashtable */
+ PKIX_CHECK(PKIX_PL_Malloc
+ (sizeof (pkix_pl_PrimHashTable),
+ (void **)&primHashTable,
+ plContext),
+ PKIX_MALLOCFAILED);
+
+ primHashTable->size = numBuckets;
+
+ /* Allocate space for the buckets */
+ PKIX_CHECK(PKIX_PL_Malloc
+ (numBuckets * sizeof (pkix_pl_HT_Elem*),
+ (void **)&primHashTable->buckets,
+ plContext),
+ PKIX_MALLOCFAILED);
+
+ for (i = 0; i < numBuckets; i++) {
+ primHashTable->buckets[i] = NULL;
+ }
+
+ *pResult = primHashTable;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_FREE(primHashTable);
+ }
+
+ PKIX_RETURN(HASHTABLE);
+}
+
+/*
+ * FUNCTION: pkix_pl_PrimHashTable_Add
+ * DESCRIPTION:
+ *
+ * Adds the value pointed to by "value" to the PrimHashTable pointed to by
+ * "ht" using the key pointed to by "key" and the hashCode value equal to
+ * "hashCode", using the function pointed to by "keyComp" to compare keys.
+ * Assumes the key is either a PKIX_UInt32 or a PKIX_PL_Object. If the value
+ * already exists in the hashtable, this function returns a non-fatal error.
+ *
+ * PARAMETERS:
+ * "ht"
+ * Address of PrimHashtable to insert into. Must be non-NULL.
+ * "key"
+ * Address of key. Typically a PKIX_UInt32 or PKIX_PL_Object.
+ * Must be non-NULL.
+ * "value"
+ * Address of Object to be added to PrimHashtable. Must be non-NULL.
+ * "hashCode"
+ * Hashcode value of the key.
+ * "keyComp"
+ * Address of function used to determine if two keys are equal.
+ * If NULL, pkix_pl_KeyComparator_Default is used.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Not Thread Safe - assumes exclusive access to "ht"
+ * (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HashTable Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_PrimHashTable_Add(
+ pkix_pl_PrimHashTable *ht,
+ void *key,
+ void *value,
+ PKIX_UInt32 hashCode,
+ PKIX_PL_EqualsCallback keyComp,
+ void *plContext)
+{
+ pkix_pl_HT_Elem **elemPtr = NULL;
+ pkix_pl_HT_Elem *element = NULL;
+ PKIX_Boolean compResult = PKIX_FALSE;
+
+ PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Add");
+ PKIX_NULLCHECK_THREE(ht, key, value);
+
+ for (elemPtr = &((ht->buckets)[hashCode%ht->size]), element = *elemPtr;
+ element != NULL; elemPtr = &(element->next), element = *elemPtr) {
+
+ if (element->hashCode != hashCode){
+ /* no possibility of a match */
+ continue;
+ }
+
+ if (keyComp == NULL){
+ PKIX_CHECK(pkix_pl_KeyComparator_Default
+ ((PKIX_UInt32 *)key,
+ (PKIX_UInt32 *)(element->key),
+ &compResult,
+ plContext),
+ PKIX_COULDNOTTESTWHETHERKEYSEQUAL);
+ } else {
+ PKIX_CHECK(keyComp
+ ((PKIX_PL_Object *)key,
+ (PKIX_PL_Object *)(element->key),
+ &compResult,
+ plContext),
+ PKIX_COULDNOTTESTWHETHERKEYSEQUAL);
+ }
+
+ if ((element->hashCode == hashCode) &&
+ (compResult == PKIX_TRUE)){
+ /* Same key already exists in the table */
+ PKIX_ERROR(PKIX_ATTEMPTTOADDDUPLICATEKEY);
+ }
+ }
+
+ /* Next Element should be NULL at this point */
+ if (element != NULL) {
+ PKIX_ERROR(PKIX_ERRORTRAVERSINGBUCKET);
+ }
+
+ /* Create a new HT_Elem */
+ PKIX_CHECK(PKIX_PL_Malloc
+ (sizeof (pkix_pl_HT_Elem), (void **)elemPtr, plContext),
+ PKIX_MALLOCFAILED);
+
+ element = *elemPtr;
+
+ element->key = key;
+ element->value = value;
+ element->hashCode = hashCode;
+ element->next = NULL;
+
+cleanup:
+
+ PKIX_RETURN(HASHTABLE);
+}
+
+/*
+ * FUNCTION: pkix_pl_PrimHashTable_Remove
+ * DESCRIPTION:
+ *
+ * Removes any objects with the key pointed to by "key" and hashCode value
+ * equal to "hashCode" from the PrimHashtable pointed to by "ht", using the
+ * function pointed to by "keyComp" to compare keys, and stores the object's
+ * value at "pResult". Assumes "key" is a PKIX_UInt32 or a PKIX_PL_Object.
+ * This function sets "pResult" to NULL if the key is not in the hashtable.
+ *
+ * PARAMETERS:
+ * "ht"
+ * Address of PrimHashtable to remove object. Must be non-NULL.
+ * "key"
+ * Address of key for lookup. Typically a PKIX_UInt32 or PKIX_PL_Object.
+ * Must be non-NULL.
+ * "value"
+ * Address of Object to be added to PrimHashtable. Must be non-NULL.
+ * "hashCode"
+ * Hashcode value of the key.
+ * "keyComp"
+ * Address of function used to determine if two keys are equal.
+ * If NULL, pkix_pl_KeyComparator_Default is used.
+ * "pResult"
+ * Address where value will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Not Thread Safe - assumes exclusive access to "ht"
+ * (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HashTable Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_PrimHashTable_Remove(
+ pkix_pl_PrimHashTable *ht,
+ void *key,
+ PKIX_UInt32 hashCode,
+ PKIX_PL_EqualsCallback keyComp,
+ void **pKey,
+ void **pValue,
+ void *plContext)
+{
+ pkix_pl_HT_Elem *element = NULL;
+ pkix_pl_HT_Elem *prior = NULL;
+ PKIX_Boolean compResult;
+
+ PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Remove");
+ PKIX_NULLCHECK_FOUR(ht, key, pKey, pValue);
+
+ *pKey = NULL;
+ *pValue = NULL;
+
+ for (element = ht->buckets[hashCode%ht->size], prior = element;
+ (element != NULL);
+ prior = element, element = element->next) {
+
+ if (element->hashCode != hashCode){
+ /* no possibility of a match */
+ continue;
+ }
+
+ if (keyComp == NULL){
+ PKIX_CHECK(pkix_pl_KeyComparator_Default
+ ((PKIX_UInt32 *)key,
+ (PKIX_UInt32 *)(element->key),
+ &compResult,
+ plContext),
+ PKIX_COULDNOTTESTWHETHERKEYSEQUAL);
+ } else {
+ PKIX_CHECK(keyComp
+ ((PKIX_PL_Object *)key,
+ (PKIX_PL_Object *)(element->key),
+ &compResult,
+ plContext),
+ PKIX_COULDNOTTESTWHETHERKEYSEQUAL);
+ }
+
+ if ((element->hashCode == hashCode) &&
+ (compResult == PKIX_TRUE)){
+ if (element != prior) {
+ prior->next = element->next;
+ } else {
+ ht->buckets[hashCode%ht->size] = element->next;
+ }
+ *pKey = element->key;
+ *pValue = element->value;
+ element->key = NULL;
+ element->value = NULL;
+ element->next = NULL;
+ PKIX_FREE(element);
+ goto cleanup;
+ }
+ }
+
+cleanup:
+
+ PKIX_RETURN(HASHTABLE);
+}
+
+
+/*
+ * FUNCTION: pkix_pl_HashTableLookup
+ * DESCRIPTION:
+ *
+ * Looks up object using the key pointed to by "key" and hashCode value
+ * equal to "hashCode" from the PrimHashtable pointed to by "ht", using the
+ * function pointed to by "keyComp" to compare keys, and stores the object's
+ * value at "pResult". Assumes "key" is a PKIX_UInt32 or a PKIX_PL_Object.
+ * This function sets "pResult" to NULL if the key is not in the hashtable.
+ *
+ * PARAMETERS:
+ * "ht"
+ * Address of PrimHashtable to lookup object from. Must be non-NULL.
+ * "key"
+ * Address of key for lookup. Typically a PKIX_UInt32 or PKIX_PL_Object.
+ * Must be non-NULL.
+ * "keyComp"
+ * Address of function used to determine if two keys are equal.
+ * If NULL, pkix_pl_KeyComparator_Default is used.
+ * "hashCode"
+ * Hashcode value of the key.
+ * "pResult"
+ * Address where value will be stored. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Conditionally Thread Safe
+ * (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_PrimHashTable_Lookup(
+ pkix_pl_PrimHashTable *ht,
+ void *key,
+ PKIX_UInt32 hashCode,
+ PKIX_PL_EqualsCallback keyComp,
+ void **pResult,
+ void *plContext)
+{
+ pkix_pl_HT_Elem *element = NULL;
+ PKIX_Boolean compResult = PKIX_FALSE;
+
+ PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Lookup");
+ PKIX_NULLCHECK_THREE(ht, key, pResult);
+
+ *pResult = NULL;
+
+ for (element = (ht->buckets)[hashCode%ht->size];
+ (element != NULL) && (*pResult == NULL);
+ element = element->next) {
+
+ if (element->hashCode != hashCode){
+ /* no possibility of a match */
+ continue;
+ }
+
+ if (keyComp == NULL){
+ PKIX_CHECK(pkix_pl_KeyComparator_Default
+ ((PKIX_UInt32 *)key,
+ (PKIX_UInt32 *)(element->key),
+ &compResult,
+ plContext),
+ PKIX_COULDNOTTESTWHETHERKEYSEQUAL);
+ } else {
+ pkixErrorResult =
+ keyComp((PKIX_PL_Object *)key,
+ (PKIX_PL_Object *)(element->key),
+ &compResult,
+ plContext);
+ if (pkixErrorResult) {
+ pkixErrorClass = PKIX_FATAL_ERROR;
+ pkixErrorCode = PKIX_COULDNOTTESTWHETHERKEYSEQUAL;
+ goto cleanup;
+ }
+ }
+
+ if ((element->hashCode == hashCode) &&
+ (compResult == PKIX_TRUE)){
+ *pResult = element->value;
+ goto cleanup;
+ }
+ }
+
+ /* if we've reached here, specified key doesn't exist in hashtable */
+ *pResult = NULL;
+
+cleanup:
+
+ PKIX_RETURN(HASHTABLE);
+}
+
+/*
+ * FUNCTION: pkix_pl_PrimHashTable_Destroy
+ *
+ * Destroys PrimHashTable pointed to by "ht".
+ *
+ * PARAMETERS:
+ * "ht"
+ * Address of PrimHashtable to free. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Not Thread Safe - assumes exclusive access to "ht"
+ * (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS
+ * Returns NULL if the function succeeds.
+ * Returns a HashTable Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_PrimHashTable_Destroy(
+ pkix_pl_PrimHashTable *ht,
+ void *plContext)
+{
+ pkix_pl_HT_Elem *element = NULL;
+ pkix_pl_HT_Elem *temp = NULL;
+ PKIX_UInt32 i;
+
+ PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Destroy");
+ PKIX_NULLCHECK_ONE(ht);
+
+ /* Free each element (list) */
+ for (i = 0; i < ht->size; i++) {
+ for (element = ht->buckets[i];
+ element != NULL;
+ element = temp) {
+ temp = element->next;
+ element->value = NULL;
+ element->key = NULL;
+ element->hashCode = 0;
+ element->next = NULL;
+ PKIX_FREE(element);
+ }
+ }
+
+ /* Free the pointer to the list array */
+ PKIX_FREE(ht->buckets);
+ ht->size = 0;
+
+ /* Free the table itself */
+ PKIX_FREE(ht);
+
+ PKIX_RETURN(HASHTABLE);
+}
+
+/*
+ * FUNCTION: pkix_pl_PrimHashTable_GetBucketSize
+ * DESCRIPTION:
+ *
+ * Retruns number of entries in the bucket the "hashCode" is designated in
+ * the hashtable "ht" in the address "pBucketSize".
+ *
+ * PARAMETERS:
+ * "ht"
+ * Address of PrimHashtable to get entries count. Must be non-NULL.
+ * "hashCode"
+ * Hashcode value of the key.
+ * "pBucketSize"
+ * Address that an PKIX_UInt32 is returned for number of entries in the
+ * bucket associated with the hashCode. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Not Thread Safe - assumes exclusive access to "ht"
+ * (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HashTable Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_PrimHashTable_GetBucketSize(
+ pkix_pl_PrimHashTable *ht,
+ PKIX_UInt32 hashCode,
+ PKIX_UInt32 *pBucketSize,
+ void *plContext)
+{
+ pkix_pl_HT_Elem **elemPtr = NULL;
+ pkix_pl_HT_Elem *element = NULL;
+ PKIX_UInt32 bucketSize = 0;
+
+ PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_GetBucketSize");
+ PKIX_NULLCHECK_TWO(ht, pBucketSize);
+
+ for (elemPtr = &((ht->buckets)[hashCode%ht->size]), element = *elemPtr;
+ element != NULL; elemPtr = &(element->next), element = *elemPtr) {
+ bucketSize++;
+ }
+
+ *pBucketSize = bucketSize;
+
+ PKIX_RETURN(HASHTABLE);
+}
+
+/*
+ * FUNCTION: pkix_pl_PrimHashTable_RemoveFIFO
+ * DESCRIPTION:
+ *
+ * Remove the first entry in the bucket the "hashCode" is designated in
+ * the hashtable "ht". Since new entry is added at end of the link list
+ * the first one is the oldest (FI) therefore removed first (FO).
+ *
+ * PARAMETERS:
+ * "ht"
+ * Address of PrimHashtable to get entries count. Must be non-NULL.
+ * "hashCode"
+ * Hashcode value of the key.
+ * "pKey"
+ * Address of key of the entry deleted. Must be non-NULL.
+ * "pValue"
+ * Address of Value of the entry deleted. Must be non-NULL.
+ * "plContext"
+ * Platform-specific context pointer.
+ * THREAD SAFETY:
+ * Not Thread Safe - assumes exclusive access to "ht"
+ * (see Thread Safety Definitions in Programmer's Guide)
+ * RETURNS:
+ * Returns NULL if the function succeeds.
+ * Returns a HashTable Error if the function fails in a non-fatal way.
+ * Returns a Fatal Error if the function fails in an unrecoverable way.
+ */
+PKIX_Error *
+pkix_pl_PrimHashTable_RemoveFIFO(
+ pkix_pl_PrimHashTable *ht,
+ PKIX_UInt32 hashCode,
+ void **pKey,
+ void **pValue,
+ void *plContext)
+{
+ pkix_pl_HT_Elem *element = NULL;
+
+ PKIX_ENTER(HASHTABLE, "pkix_pl_PrimHashTable_Remove");
+ PKIX_NULLCHECK_THREE(ht, pKey, pValue);
+
+ element = (ht->buckets)[hashCode%ht->size];
+
+ if (element != NULL) {
+
+ *pKey = element->key;
+ *pValue = element->value;
+ ht->buckets[hashCode%ht->size] = element->next;
+ element->key = NULL;
+ element->value = NULL;
+ element->next = NULL;
+ PKIX_FREE(element);
+ }
+
+ PKIX_RETURN(HASHTABLE);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_primhash.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_primhash.h
new file mode 100755
index 000000000..b889e2e91
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_primhash.h
@@ -0,0 +1,102 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_primhash.h
+ *
+ * Primitive Hashtable Definition
+ *
+ */
+
+#ifndef _PKIX_PL_PRIMHASH_H
+#define _PKIX_PL_PRIMHASH_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct pkix_pl_HT_Elem pkix_pl_HT_Elem;
+
+typedef struct pkix_pl_PrimHashTable pkix_pl_PrimHashTable;
+
+typedef struct pkix_pl_Integer pkix_pl_Integer;
+
+struct pkix_pl_Integer{
+ PKIX_UInt32 ht_int;
+};
+
+struct pkix_pl_HT_Elem {
+ void *key;
+ void *value;
+ PKIX_UInt32 hashCode;
+ pkix_pl_HT_Elem *next;
+};
+
+struct pkix_pl_PrimHashTable {
+ pkix_pl_HT_Elem **buckets;
+ PKIX_UInt32 size;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_pl_PrimHashTable_Create(
+ PKIX_UInt32 numBuckets,
+ pkix_pl_PrimHashTable **pResult,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_PrimHashTable_Add(
+ pkix_pl_PrimHashTable *ht,
+ void *key,
+ void *value,
+ PKIX_UInt32 hashCode,
+ PKIX_PL_EqualsCallback keyComp,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_PrimHashTable_Remove(
+ pkix_pl_PrimHashTable *ht,
+ void *key,
+ PKIX_UInt32 hashCode,
+ PKIX_PL_EqualsCallback keyComp,
+ void **pKey,
+ void **pValue,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_PrimHashTable_Lookup(
+ pkix_pl_PrimHashTable *ht,
+ void *key,
+ PKIX_UInt32 hashCode,
+ PKIX_PL_EqualsCallback keyComp,
+ void **pResult,
+ void *plContext);
+
+PKIX_Error*
+pkix_pl_PrimHashTable_Destroy(
+ pkix_pl_PrimHashTable *ht,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_PrimHashTable_GetBucketSize(
+ pkix_pl_PrimHashTable *ht,
+ PKIX_UInt32 hashCode,
+ PKIX_UInt32 *pBucketSize,
+ void *plContext);
+
+PKIX_Error *
+pkix_pl_PrimHashTable_RemoveFIFO(
+ pkix_pl_PrimHashTable *ht,
+ PKIX_UInt32 hashCode,
+ void **pKey,
+ void **pValue,
+ void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_PRIMHASH_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_rwlock.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_rwlock.c
new file mode 100755
index 000000000..662931e98
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_rwlock.c
@@ -0,0 +1,217 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_rwlock.c
+ *
+ * Read/Write Lock Functions
+ *
+ */
+
+#include "pkix_pl_rwlock.h"
+
+/* --Private-Functions-------------------------------------------- */
+
+static PKIX_Error *
+pkix_pl_RWLock_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_RWLock* rwlock = NULL;
+
+ PKIX_ENTER(RWLOCK, "pkix_pl_RWLock_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_RWLOCK_TYPE, plContext),
+ PKIX_OBJECTNOTRWLOCK);
+
+ rwlock = (PKIX_PL_RWLock*) object;
+
+ PKIX_RWLOCK_DEBUG("Calling PR_DestroyRWLock)\n");
+ PR_DestroyRWLock(rwlock->lock);
+ rwlock->lock = NULL;
+
+cleanup:
+
+ PKIX_RETURN(RWLOCK);
+}
+
+/*
+ * FUNCTION: pkix_pl_RWLock_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_RWLOCK_TYPE and its related functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_RWLock_RegisterSelf(
+ void *plContext)
+{
+
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(RWLOCK, "pkix_pl_RWLock_RegisterSelf");
+
+ entry.description = "RWLock";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_RWLock);
+ entry.destructor = pkix_pl_RWLock_Destroy;
+ entry.equalsFunction = NULL;
+ entry.hashcodeFunction = NULL;
+ entry.toStringFunction = NULL;
+ entry.comparator = NULL;
+ entry.duplicateFunction = NULL;
+
+ systemClasses[PKIX_RWLOCK_TYPE] = entry;
+
+ PKIX_RETURN(RWLOCK);
+}
+
+/* --Public-Functions--------------------------------------------- */
+
+PKIX_Error *
+PKIX_PL_RWLock_Create(
+ PKIX_PL_RWLock **pNewLock,
+ void *plContext)
+{
+ PKIX_PL_RWLock *rwLock = NULL;
+
+ PKIX_ENTER(RWLOCK, "PKIX_PL_RWLock_Create");
+ PKIX_NULLCHECK_ONE(pNewLock);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_RWLOCK_TYPE,
+ sizeof (PKIX_PL_RWLock),
+ (PKIX_PL_Object **)&rwLock,
+ plContext),
+ PKIX_ERRORALLOCATINGRWLOCK);
+
+ PKIX_RWLOCK_DEBUG("\tCalling PR_NewRWLock)\n");
+ rwLock->lock = PR_NewRWLock(PR_RWLOCK_RANK_NONE, "PKIX RWLock");
+
+ if (rwLock->lock == NULL) {
+ PKIX_DECREF(rwLock);
+ PKIX_ERROR(PKIX_OUTOFMEMORY);
+ }
+
+ rwLock->readCount = 0;
+ rwLock->writeLocked = PKIX_FALSE;
+
+ *pNewLock = rwLock;
+
+cleanup:
+
+ PKIX_RETURN(RWLOCK);
+}
+
+PKIX_Error *
+PKIX_PL_AcquireReaderLock(
+ PKIX_PL_RWLock *lock,
+ void *plContext)
+{
+ PKIX_ENTER(RWLOCK, "PKIX_PL_AcquireReaderLock");
+ PKIX_NULLCHECK_ONE(lock);
+
+ PKIX_RWLOCK_DEBUG("\tCalling PR_RWLock_Rlock)\n");
+ (void) PR_RWLock_Rlock(lock->lock);
+
+ lock->readCount++;
+
+ PKIX_RETURN(RWLOCK);
+}
+
+PKIX_Error *
+PKIX_PL_ReleaseReaderLock(
+ PKIX_PL_RWLock *lock,
+ void *plContext)
+{
+ PKIX_ENTER(RWLOCK, "PKIX_PL_ReleaseReaderLock");
+ PKIX_NULLCHECK_ONE(lock);
+
+ PKIX_RWLOCK_DEBUG("\tCalling PR_RWLock_Unlock)\n");
+ (void) PR_RWLock_Unlock(lock->lock);
+
+ lock->readCount--;
+
+ PKIX_RETURN(RWLOCK);
+}
+
+PKIX_Error *
+PKIX_PL_IsReaderLockHeld(
+ PKIX_PL_RWLock *lock,
+ PKIX_Boolean *pIsHeld,
+ void *plContext)
+{
+ PKIX_ENTER(RWLOCK, "PKIX_PL_IsReaderLockHeld");
+ PKIX_NULLCHECK_TWO(lock, pIsHeld);
+
+ *pIsHeld = (lock->readCount > 0)?PKIX_TRUE:PKIX_FALSE;
+
+ PKIX_RETURN(RWLOCK);
+}
+
+PKIX_Error *
+PKIX_PL_AcquireWriterLock(
+ PKIX_PL_RWLock *lock,
+ void *plContext)
+{
+ PKIX_ENTER(RWLOCK, "PKIX_PL_AcquireWriterLock");
+ PKIX_NULLCHECK_ONE(lock);
+
+ PKIX_RWLOCK_DEBUG("\tCalling PR_RWLock_Wlock\n");
+ (void) PR_RWLock_Wlock(lock->lock);
+
+ if (lock->readCount > 0) {
+ PKIX_ERROR(PKIX_LOCKHASNONZEROREADCOUNT);
+ }
+
+ /* We should never acquire a write lock if the lock is held */
+ lock->writeLocked = PKIX_TRUE;
+
+cleanup:
+
+ PKIX_RETURN(RWLOCK);
+}
+
+PKIX_Error *
+PKIX_PL_ReleaseWriterLock(
+ PKIX_PL_RWLock *lock,
+ void *plContext)
+{
+ PKIX_ENTER(RWLOCK, "PKIX_PL_ReleaseWriterLock");
+ PKIX_NULLCHECK_ONE(lock);
+
+ if (lock->readCount > 0) {
+ PKIX_ERROR(PKIX_LOCKHASNONZEROREADCOUNT);
+ }
+
+ PKIX_RWLOCK_DEBUG("\tCalling PR_RWLock_Unlock)\n");
+ (void) PR_RWLock_Unlock(lock->lock);
+
+ /* XXX Need to think about thread safety here */
+ /* There should be a single lock holder */
+ lock->writeLocked = PKIX_FALSE;
+
+cleanup:
+
+ PKIX_RETURN(RWLOCK);
+}
+
+PKIX_Error *
+PKIX_PL_IsWriterLockHeld(
+ PKIX_PL_RWLock *lock,
+ PKIX_Boolean *pIsHeld,
+ void *plContext)
+{
+ PKIX_ENTER(RWLOCK, "PKIX_PL_IsWriterLockHeld");
+ PKIX_NULLCHECK_TWO(lock, pIsHeld);
+
+ *pIsHeld = lock->writeLocked;
+
+ PKIX_RETURN(RWLOCK);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_rwlock.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_rwlock.h
new file mode 100755
index 000000000..fd6465950
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_rwlock.h
@@ -0,0 +1,35 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_rwlock.h
+ *
+ * Read/Write Lock Definition
+ *
+ */
+
+#ifndef _PKIX_PL_RWLOCK_H
+#define _PKIX_PL_RWLOCK_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_RWLockStruct {
+ PRRWLock* lock;
+ PKIX_UInt32 readCount;
+ PKIX_Boolean writeLocked;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_pl_RWLock_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_RWLOCK_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.c b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.c
new file mode 100755
index 000000000..8bfa2c996
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.c
@@ -0,0 +1,621 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_string.c
+ *
+ * String Object Functions
+ *
+ */
+
+#include "pkix_pl_string.h"
+
+/* --Private-String-Functions------------------------------------- */
+
+/*
+ * FUNCTION: pkix_pl_String_Comparator
+ * (see comments for PKIX_PL_ComparatorCallback in pkix_pl_system.h)
+ *
+ * NOTE:
+ * This function is a utility function called by pkix_pl_String_Equals().
+ * It is not officially registered as a comparator.
+ */
+static PKIX_Error *
+pkix_pl_String_Comparator(
+ PKIX_PL_String *firstString,
+ PKIX_PL_String *secondString,
+ PKIX_Int32 *pResult,
+ void *plContext)
+{
+ PKIX_UInt32 i;
+ PKIX_Int32 result;
+ unsigned char *p1 = NULL;
+ unsigned char *p2 = NULL;
+
+ PKIX_ENTER(STRING, "pkix_pl_String_Comparator");
+ PKIX_NULLCHECK_THREE(firstString, secondString, pResult);
+
+ result = 0;
+
+ p1 = (unsigned char*) firstString->utf16String;
+ p2 = (unsigned char*) secondString->utf16String;
+
+ /* Compare characters until you find a difference */
+ for (i = 0; ((i < firstString->utf16Length) &&
+ (i < secondString->utf16Length) &&
+ result == 0); i++, p1++, p2++) {
+ if (*p1 < *p2){
+ result = -1;
+ } else if (*p1 > *p2){
+ result = 1;
+ }
+ }
+
+ /* If two arrays are identical so far, the longer one is greater */
+ if (result == 0) {
+ if (firstString->utf16Length < secondString->utf16Length) {
+ result = -1;
+ } else if (firstString->utf16Length >
+ secondString->utf16Length) {
+ result = 1;
+ }
+ }
+
+ *pResult = result;
+
+ PKIX_RETURN(STRING);
+}
+
+/*
+ * FUNCTION: pkix_pl_String_Destroy
+ * (see comments for PKIX_PL_DestructorCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_String_Destroy(
+ PKIX_PL_Object *object,
+ void *plContext)
+{
+ PKIX_PL_String *string = NULL;
+
+ PKIX_ENTER(STRING, "pkix_pl_String_Destroy");
+ PKIX_NULLCHECK_ONE(object);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext),
+ PKIX_ARGUMENTNOTSTRING);
+
+ string = (PKIX_PL_String*)object;
+
+ /* XXX For debugging Destroy EscASCII String */
+ if (string->escAsciiString != NULL) {
+ PKIX_FREE(string->escAsciiString);
+ string->escAsciiString = NULL;
+ string->escAsciiLength = 0;
+ }
+
+ /* Destroy UTF16 String */
+ if (string->utf16String != NULL) {
+ PKIX_FREE(string->utf16String);
+ string->utf16String = NULL;
+ string->utf16Length = 0;
+ }
+
+cleanup:
+
+ PKIX_RETURN(STRING);
+}
+
+/*
+ * FUNCTION: pkix_pl_String_ToString
+ * (see comments for PKIX_PL_ToStringCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_String_ToString(
+ PKIX_PL_Object *object,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_String *string = NULL;
+ char *ascii = NULL;
+ PKIX_UInt32 length;
+
+ PKIX_ENTER(STRING, "pkix_pl_String_ToString");
+ PKIX_NULLCHECK_TWO(object, pString);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext),
+ PKIX_ARGUMENTNOTSTRING);
+
+ string = (PKIX_PL_String*)object;
+
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ (string, PKIX_ESCASCII, (void **)&ascii, &length, plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, ascii, 0, pString, plContext),
+ PKIX_STRINGCREATEFAILED);
+
+ goto cleanup;
+
+cleanup:
+
+ PKIX_FREE(ascii);
+
+ PKIX_RETURN(STRING);
+}
+
+/*
+ * FUNCTION: pkix_pl_String_Equals
+ * (see comments for PKIX_PL_EqualsCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_String_Equals(
+ PKIX_PL_Object *firstObject,
+ PKIX_PL_Object *secondObject,
+ PKIX_Boolean *pResult,
+ void *plContext)
+{
+ PKIX_UInt32 secondType;
+ PKIX_Int32 cmpResult = 0;
+
+ PKIX_ENTER(STRING, "pkix_pl_String_Equals");
+ PKIX_NULLCHECK_THREE(firstObject, secondObject, pResult);
+
+ /* Sanity check: Test that "firstObject" is a Strings */
+ PKIX_CHECK(pkix_CheckType(firstObject, PKIX_STRING_TYPE, plContext),
+ PKIX_FIRSTOBJECTNOTSTRING);
+
+ /* "SecondObject" doesn't have to be a string */
+ PKIX_CHECK(PKIX_PL_Object_GetType
+ (secondObject, &secondType, plContext),
+ PKIX_COULDNOTGETTYPEOFSECONDARGUMENT);
+
+ /* If types differ, then we will return false */
+ *pResult = PKIX_FALSE;
+
+ if (secondType != PKIX_STRING_TYPE) goto cleanup;
+
+ /* It's safe to cast here */
+ PKIX_CHECK(pkix_pl_String_Comparator
+ ((PKIX_PL_String*)firstObject,
+ (PKIX_PL_String*)secondObject,
+ &cmpResult,
+ plContext),
+ PKIX_STRINGCOMPARATORFAILED);
+
+ /* Strings are equal iff Comparator Result is 0 */
+ *pResult = (cmpResult == 0);
+
+cleanup:
+
+ PKIX_RETURN(STRING);
+}
+
+/*
+ * FUNCTION: pkix_pl_String_Hashcode
+ * (see comments for PKIX_PL_HashcodeCallback in pkix_pl_system.h)
+ */
+static PKIX_Error *
+pkix_pl_String_Hashcode(
+ PKIX_PL_Object *object,
+ PKIX_UInt32 *pHashcode,
+ void *plContext)
+{
+ PKIX_PL_String *string = NULL;
+
+ PKIX_ENTER(STRING, "pkix_pl_String_Hashcode");
+ PKIX_NULLCHECK_TWO(object, pHashcode);
+
+ PKIX_CHECK(pkix_CheckType(object, PKIX_STRING_TYPE, plContext),
+ PKIX_OBJECTNOTSTRING);
+
+ string = (PKIX_PL_String*)object;
+
+ PKIX_CHECK(pkix_hash
+ ((const unsigned char *)string->utf16String,
+ string->utf16Length,
+ pHashcode,
+ plContext),
+ PKIX_HASHFAILED);
+
+cleanup:
+
+ PKIX_RETURN(STRING);
+}
+
+/*
+ * FUNCTION: pkix_pl_String_RegisterSelf
+ * DESCRIPTION:
+ * Registers PKIX_STRING_TYPE and its related functions with systemClasses[]
+ * THREAD SAFETY:
+ * Not Thread Safe - for performance and complexity reasons
+ *
+ * Since this function is only called by PKIX_PL_Initialize, which should
+ * only be called once, it is acceptable that this function is not
+ * thread-safe.
+ */
+PKIX_Error *
+pkix_pl_String_RegisterSelf(
+ void *plContext)
+{
+ extern pkix_ClassTable_Entry systemClasses[PKIX_NUMTYPES];
+ pkix_ClassTable_Entry entry;
+
+ PKIX_ENTER(STRING, "pkix_pl_String_RegisterSelf");
+
+ entry.description = "String";
+ entry.objCounter = 0;
+ entry.typeObjectSize = sizeof(PKIX_PL_String);
+ entry.destructor = pkix_pl_String_Destroy;
+ entry.equalsFunction = pkix_pl_String_Equals;
+ entry.hashcodeFunction = pkix_pl_String_Hashcode;
+ entry.toStringFunction = pkix_pl_String_ToString;
+ entry.comparator = NULL;
+ entry.duplicateFunction = pkix_duplicateImmutable;
+
+ systemClasses[PKIX_STRING_TYPE] = entry;
+
+ PKIX_RETURN(STRING);
+}
+
+
+/* --Public-String-Functions----------------------------------------- */
+
+/*
+ * FUNCTION: PKIX_PL_String_Create (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_String_Create(
+ PKIX_UInt32 fmtIndicator,
+ const void *stringRep,
+ PKIX_UInt32 stringLen,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_PL_String *string = NULL;
+ unsigned char *utf16Char = NULL;
+ PKIX_UInt32 i;
+
+ PKIX_ENTER(STRING, "PKIX_PL_String_Create");
+ PKIX_NULLCHECK_TWO(pString, stringRep);
+
+ PKIX_CHECK(PKIX_PL_Object_Alloc
+ (PKIX_STRING_TYPE,
+ sizeof (PKIX_PL_String),
+ (PKIX_PL_Object **)&string,
+ plContext),
+ PKIX_COULDNOTALLOCATENEWSTRINGOBJECT);
+
+ string->utf16String = NULL;
+ string->utf16Length = 0;
+
+ /* XXX For Debugging */
+ string->escAsciiString = NULL;
+ string->escAsciiLength = 0;
+
+ switch (fmtIndicator) {
+ case PKIX_ESCASCII: case PKIX_ESCASCII_DEBUG:
+ PKIX_STRING_DEBUG("\tCalling PL_strlen).\n");
+ string->escAsciiLength = PL_strlen(stringRep);
+
+ /* XXX Cache for Debugging */
+ PKIX_CHECK(PKIX_PL_Malloc
+ ((string->escAsciiLength)+1,
+ (void **)&string->escAsciiString,
+ plContext),
+ PKIX_MALLOCFAILED);
+
+ (void) PORT_Memcpy
+ (string->escAsciiString,
+ (void *)((char *)stringRep),
+ (string->escAsciiLength)+1);
+
+ /* Convert the EscASCII string to UTF16 */
+ PKIX_CHECK(pkix_EscASCII_to_UTF16
+ (string->escAsciiString,
+ string->escAsciiLength,
+ (fmtIndicator == PKIX_ESCASCII_DEBUG),
+ &string->utf16String,
+ &string->utf16Length,
+ plContext),
+ PKIX_ESCASCIITOUTF16FAILED);
+ break;
+ case PKIX_UTF8:
+ /* Convert the UTF8 string to UTF16 */
+ PKIX_CHECK(pkix_UTF8_to_UTF16
+ (stringRep,
+ stringLen,
+ &string->utf16String,
+ &string->utf16Length,
+ plContext),
+ PKIX_UTF8TOUTF16FAILED);
+ break;
+ case PKIX_UTF16:
+ /* UTF16 Strings must be even in length */
+ if (stringLen%2 == 1) {
+ PKIX_DECREF(string);
+ PKIX_ERROR(PKIX_UTF16ALIGNMENTERROR);
+ }
+
+ utf16Char = (unsigned char *)stringRep;
+
+ /* Make sure this is a valid UTF-16 String */
+ for (i = 0; \
+ (i < stringLen) && (pkixErrorResult == NULL); \
+ i += 2) {
+ /* Check that surrogate pairs are valid */
+ if ((utf16Char[i] >= 0xD8)&&
+ (utf16Char[i] <= 0xDB)) {
+ if ((i+2) >= stringLen) {
+ PKIX_ERROR(PKIX_UTF16HIGHZONEALIGNMENTERROR);
+ /* Second pair should be DC00-DFFF */
+ } else if (!((utf16Char[i+2] >= 0xDC)&&
+ (utf16Char[i+2] <= 0xDF))) {
+ PKIX_ERROR(PKIX_UTF16LOWZONEERROR);
+ } else {
+ /* Surrogate quartet is valid. */
+ i += 2;
+ }
+ }
+ }
+
+ /* Create UTF16 String */
+ string->utf16Length = stringLen;
+
+ /* Alloc space for string */
+ PKIX_CHECK(PKIX_PL_Malloc
+ (stringLen, &string->utf16String, plContext),
+ PKIX_MALLOCFAILED);
+
+ PKIX_STRING_DEBUG("\tCalling PORT_Memcpy).\n");
+ (void) PORT_Memcpy
+ (string->utf16String, stringRep, stringLen);
+ break;
+
+ default:
+ PKIX_ERROR(PKIX_UNKNOWNFORMAT);
+ }
+
+ *pString = string;
+
+cleanup:
+
+ if (PKIX_ERROR_RECEIVED){
+ PKIX_DECREF(string);
+ }
+
+ PKIX_RETURN(STRING);
+}
+
+/*
+ * FUNCTION: PKIX_PL_Sprintf (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_Sprintf(
+ PKIX_PL_String **pOut,
+ void *plContext,
+ const PKIX_PL_String *fmt,
+ ...)
+{
+ PKIX_PL_String *tempString = NULL;
+ PKIX_UInt32 tempUInt = 0;
+ void *pArg = NULL;
+ char *asciiText = NULL;
+ char *asciiFormat = NULL;
+ char *convertedAsciiFormat = NULL;
+ char *convertedAsciiFormatBase = NULL;
+ va_list args;
+ PKIX_UInt32 length, i, j, dummyLen;
+
+ PKIX_ENTER(STRING, "PKIX_PL_Sprintf");
+ PKIX_NULLCHECK_TWO(pOut, fmt);
+
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ ((PKIX_PL_String *)fmt,
+ PKIX_ESCASCII,
+ (void **)&asciiFormat,
+ &length,
+ plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+
+ PKIX_STRING_DEBUG("\tCalling PR_Malloc).\n");
+ convertedAsciiFormat = PR_Malloc(length + 1);
+ if (convertedAsciiFormat == NULL)
+ PKIX_ERROR_ALLOC_ERROR();
+
+ convertedAsciiFormatBase = convertedAsciiFormat;
+
+ PKIX_STRING_DEBUG("\tCalling va_start).\n");
+ va_start(args, fmt);
+
+ i = 0;
+ j = 0;
+ while (i < length) {
+ if ((asciiFormat[i] == '%')&&((i+1) < length)) {
+ switch (asciiFormat[i+1]) {
+ case 's':
+ convertedAsciiFormat[j++] = asciiFormat[i++];
+ convertedAsciiFormat[j++] = asciiFormat[i++];
+ convertedAsciiFormat[j] = '\0';
+
+ tempString = va_arg(args, PKIX_PL_String *);
+ if (tempString != NULL) {
+ PKIX_CHECK(PKIX_PL_String_GetEncoded
+ ((PKIX_PL_String*)
+ tempString,
+ PKIX_ESCASCII,
+ &pArg,
+ &dummyLen,
+ plContext),
+ PKIX_STRINGGETENCODEDFAILED);
+ } else {
+ /* there may be a NULL in var_args */
+ pArg = NULL;
+ }
+ if (asciiText != NULL) {
+ asciiText = PR_sprintf_append(asciiText,
+ (const char *)convertedAsciiFormat,
+ pArg);
+ } else {
+ asciiText = PR_smprintf
+ ((const char *)convertedAsciiFormat,
+ pArg);
+ }
+ if (pArg != NULL) {
+ PKIX_PL_Free(pArg, plContext);
+ pArg = NULL;
+ }
+ convertedAsciiFormat += j;
+ j = 0;
+ break;
+ case 'd':
+ case 'i':
+ case 'o':
+ case 'u':
+ case 'x':
+ case 'X':
+ convertedAsciiFormat[j++] = asciiFormat[i++];
+ convertedAsciiFormat[j++] = asciiFormat[i++];
+ convertedAsciiFormat[j] = '\0';
+
+ tempUInt = va_arg(args, PKIX_UInt32);
+ if (asciiText != NULL) {
+ asciiText = PR_sprintf_append(asciiText,
+ (const char *)convertedAsciiFormat,
+ tempUInt);
+ } else {
+ asciiText = PR_smprintf
+ ((const char *)convertedAsciiFormat,
+ tempUInt);
+ }
+ convertedAsciiFormat += j;
+ j = 0;
+ break;
+ default:
+ convertedAsciiFormat[j++] = asciiFormat[i++];
+ convertedAsciiFormat[j++] = asciiFormat[i++];
+ break;
+ }
+ } else {
+ convertedAsciiFormat[j++] = asciiFormat[i++];
+ }
+ }
+
+ /* for constant string value at end of fmt */
+ if (j > 0) {
+ convertedAsciiFormat[j] = '\0';
+ if (asciiText != NULL) {
+ asciiText = PR_sprintf_append(asciiText,
+ (const char *)convertedAsciiFormat);
+ } else {
+ asciiText = PR_smprintf((const char *)convertedAsciiFormat);
+ }
+ }
+
+ va_end(args);
+
+ /* Copy temporary char * into a string object */
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, (void *)asciiText, 0, pOut, plContext),
+ PKIX_STRINGCREATEFAILED);
+
+cleanup:
+
+ PKIX_FREE(asciiFormat);
+
+ if (convertedAsciiFormatBase){
+ PR_Free(convertedAsciiFormatBase);
+ }
+
+ if (asciiText){
+ PKIX_STRING_DEBUG("\tCalling PR_smprintf_free).\n");
+ PR_smprintf_free(asciiText);
+ }
+
+ PKIX_RETURN(STRING);
+}
+
+/*
+ * FUNCTION: PKIX_PL_GetString (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_GetString(
+ /* ARGSUSED */ PKIX_UInt32 stringID,
+ char *defaultString,
+ PKIX_PL_String **pString,
+ void *plContext)
+{
+ PKIX_ENTER(STRING, "PKIX_PL_GetString");
+ PKIX_NULLCHECK_TWO(pString, defaultString);
+
+ /* XXX Optimization - use stringID for caching */
+ PKIX_CHECK(PKIX_PL_String_Create
+ (PKIX_ESCASCII, defaultString, 0, pString, plContext),
+ PKIX_STRINGCREATEFAILED);
+
+cleanup:
+
+ PKIX_RETURN(STRING);
+}
+
+/*
+ * FUNCTION: PKIX_PL_String_GetEncoded (see comments in pkix_pl_system.h)
+ */
+PKIX_Error *
+PKIX_PL_String_GetEncoded(
+ PKIX_PL_String *string,
+ PKIX_UInt32 fmtIndicator,
+ void **pStringRep,
+ PKIX_UInt32 *pLength,
+ void *plContext)
+{
+ PKIX_ENTER(STRING, "PKIX_PL_String_GetEncoded");
+ PKIX_NULLCHECK_THREE(string, pStringRep, pLength);
+
+ switch (fmtIndicator) {
+ case PKIX_ESCASCII: case PKIX_ESCASCII_DEBUG:
+ PKIX_CHECK(pkix_UTF16_to_EscASCII
+ (string->utf16String,
+ string->utf16Length,
+ (fmtIndicator == PKIX_ESCASCII_DEBUG),
+ (char **)pStringRep,
+ pLength,
+ plContext),
+ PKIX_UTF16TOESCASCIIFAILED);
+ break;
+ case PKIX_UTF8:
+ PKIX_CHECK(pkix_UTF16_to_UTF8
+ (string->utf16String,
+ string->utf16Length,
+ PKIX_FALSE,
+ pStringRep,
+ pLength,
+ plContext),
+ PKIX_UTF16TOUTF8FAILED);
+ break;
+ case PKIX_UTF8_NULL_TERM:
+ PKIX_CHECK(pkix_UTF16_to_UTF8
+ (string->utf16String,
+ string->utf16Length,
+ PKIX_TRUE,
+ pStringRep,
+ pLength,
+ plContext),
+ PKIX_UTF16TOUTF8FAILED);
+ break;
+ case PKIX_UTF16:
+ *pLength = string->utf16Length;
+
+ PKIX_CHECK(PKIX_PL_Malloc(*pLength, pStringRep, plContext),
+ PKIX_MALLOCFAILED);
+
+ PKIX_STRING_DEBUG("\tCalling PORT_Memcpy).\n");
+ (void) PORT_Memcpy(*pStringRep, string->utf16String, *pLength);
+ break;
+ default:
+ PKIX_ERROR(PKIX_UNKNOWNFORMAT);
+ }
+
+cleanup:
+
+ PKIX_RETURN(STRING);
+}
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.h b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.h
new file mode 100755
index 000000000..9270e4c56
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/pkix_pl_string.h
@@ -0,0 +1,37 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+/*
+ * pkix_pl_string.h
+ *
+ * String Object Definitions
+ *
+ */
+
+#ifndef _PKIX_PL_STRING_H
+#define _PKIX_PL_STRING_H
+
+#include "pkix_pl_common.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct PKIX_PL_StringStruct {
+ void* utf16String;
+ PKIX_UInt32 utf16Length;
+ /* XXX For Debugging */
+ char* escAsciiString;
+ PKIX_UInt32 escAsciiLength;
+};
+
+/* see source file for function documentation */
+
+PKIX_Error *
+pkix_pl_String_RegisterSelf(void *plContext);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _PKIX_PL_STRING_H */
diff --git a/security/nss/lib/libpkix/pkix_pl_nss/system/system.gyp b/security/nss/lib/libpkix/pkix_pl_nss/system/system.gyp
new file mode 100644
index 000000000..32daec93d
--- /dev/null
+++ b/security/nss/lib/libpkix/pkix_pl_nss/system/system.gyp
@@ -0,0 +1,36 @@
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, You can obtain one at http://mozilla.org/MPL/2.0/.
+{
+ 'includes': [
+ '../../../../coreconf/config.gypi'
+ ],
+ 'targets': [
+ {
+ 'target_name': 'pkixsystem',
+ 'type': 'static_library',
+ 'sources': [
+ 'pkix_pl_bigint.c',
+ 'pkix_pl_bytearray.c',
+ 'pkix_pl_common.c',
+ 'pkix_pl_error.c',
+ 'pkix_pl_hashtable.c',
+ 'pkix_pl_lifecycle.c',
+ 'pkix_pl_mem.c',
+ 'pkix_pl_monitorlock.c',
+ 'pkix_pl_mutex.c',
+ 'pkix_pl_object.c',
+ 'pkix_pl_oid.c',
+ 'pkix_pl_primhash.c',
+ 'pkix_pl_rwlock.c',
+ 'pkix_pl_string.c'
+ ],
+ 'dependencies': [
+ '<(DEPTH)/exports.gyp:nss_exports'
+ ]
+ }
+ ],
+ 'variables': {
+ 'module': 'nss'
+ }
+} \ No newline at end of file