summaryrefslogtreecommitdiff
path: root/security/nss/lib/util
diff options
context:
space:
mode:
Diffstat (limited to 'security/nss/lib/util')
-rw-r--r--security/nss/lib/util/Makefile88
-rw-r--r--security/nss/lib/util/base64.h75
-rw-r--r--security/nss/lib/util/ciferfam.h92
-rw-r--r--security/nss/lib/util/config.mk104
-rw-r--r--security/nss/lib/util/derdec.c221
-rw-r--r--security/nss/lib/util/derenc.c505
-rw-r--r--security/nss/lib/util/dersubr.c266
-rw-r--r--security/nss/lib/util/dertime.c317
-rw-r--r--security/nss/lib/util/manifest.mn105
-rw-r--r--security/nss/lib/util/nssb64.h128
-rw-r--r--security/nss/lib/util/nssb64d.c864
-rw-r--r--security/nss/lib/util/nssb64e.c765
-rw-r--r--security/nss/lib/util/nssb64t.h49
-rw-r--r--security/nss/lib/util/nssilckt.h223
-rw-r--r--security/nss/lib/util/nssilock.c530
-rw-r--r--security/nss/lib/util/nssilock.h320
-rw-r--r--security/nss/lib/util/nsslocks.h45
-rw-r--r--security/nss/lib/util/nssrwlk.c479
-rw-r--r--security/nss/lib/util/nssrwlk.h164
-rw-r--r--security/nss/lib/util/nssrwlkt.h52
-rw-r--r--security/nss/lib/util/nssutil.def234
-rw-r--r--security/nss/lib/util/nssutil.rc100
-rw-r--r--security/nss/lib/util/oidstring.c145
-rw-r--r--security/nss/lib/util/portreg.c321
-rw-r--r--security/nss/lib/util/portreg.h97
-rw-r--r--security/nss/lib/util/quickder.c912
-rw-r--r--security/nss/lib/util/secalgid.c157
-rw-r--r--security/nss/lib/util/secasn1.h320
-rw-r--r--security/nss/lib/util/secasn1d.c3273
-rw-r--r--security/nss/lib/util/secasn1e.c1647
-rw-r--r--security/nss/lib/util/secasn1t.h302
-rw-r--r--security/nss/lib/util/secasn1u.c131
-rw-r--r--security/nss/lib/util/seccomon.h119
-rw-r--r--security/nss/lib/util/secder.h211
-rw-r--r--security/nss/lib/util/secdert.h163
-rw-r--r--security/nss/lib/util/secdig.c212
-rw-r--r--security/nss/lib/util/secdig.h136
-rw-r--r--security/nss/lib/util/secdigt.h61
-rw-r--r--security/nss/lib/util/secerr.h233
-rw-r--r--security/nss/lib/util/secinit.c53
-rw-r--r--security/nss/lib/util/secitem.c322
-rw-r--r--security/nss/lib/util/secitem.h128
-rw-r--r--security/nss/lib/util/secoid.c1976
-rw-r--r--security/nss/lib/util/secoid.h152
-rw-r--r--security/nss/lib/util/secoidt.h476
-rw-r--r--security/nss/lib/util/secplcy.c117
-rw-r--r--security/nss/lib/util/secplcy.h138
-rw-r--r--security/nss/lib/util/secport.c667
-rw-r--r--security/nss/lib/util/secport.h253
-rw-r--r--security/nss/lib/util/sectime.c194
-rw-r--r--security/nss/lib/util/templates.c168
-rw-r--r--security/nss/lib/util/utf8.c1833
-rw-r--r--security/nss/lib/util/utilrename.h194
-rw-r--r--security/nss/lib/util/watcomfx.h62
54 files changed, 20899 insertions, 0 deletions
diff --git a/security/nss/lib/util/Makefile b/security/nss/lib/util/Makefile
new file mode 100644
index 000000000..afe353d31
--- /dev/null
+++ b/security/nss/lib/util/Makefile
@@ -0,0 +1,88 @@
+#! gmake
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is the Netscape security libraries.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1994-2000
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+#######################################################################
+# (1) Include initial platform-independent assignments (MANDATORY). #
+#######################################################################
+
+include manifest.mn
+
+#######################################################################
+# (2) Include "global" configuration information. (OPTIONAL) #
+#######################################################################
+
+# include $(CORE_DEPTH)/coreconf/arch.mk
+
+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
+
+test: $(OBJDIR)/test_utf8
+
+$(OBJDIR)/test_utf8: utf8.c
+ @$(MAKE_OBJDIR)
+ $(CCF) -o $(OBJDIR)/test_utf8 -DTEST_UTF8 utf8.c $(OS_LIBS)
diff --git a/security/nss/lib/util/base64.h b/security/nss/lib/util/base64.h
new file mode 100644
index 000000000..e025844c3
--- /dev/null
+++ b/security/nss/lib/util/base64.h
@@ -0,0 +1,75 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * base64.h - prototypes for base64 encoding/decoding
+ * Note: These functions are deprecated; see nssb64.h for new routines.
+ *
+ * $Id$
+ */
+#ifndef _BASE64_H_
+#define _BASE64_H_
+
+#include "utilrename.h"
+#include "seccomon.h"
+
+SEC_BEGIN_PROTOS
+
+/*
+** Return an PORT_Alloc'd ascii string which is the base64 encoded
+** version of the input string.
+*/
+extern char *BTOA_DataToAscii(const unsigned char *data, unsigned int len);
+
+/*
+** Return an PORT_Alloc'd string which is the base64 decoded version
+** of the input string; set *lenp to the length of the returned data.
+*/
+extern unsigned char *ATOB_AsciiToData(const char *string, unsigned int *lenp);
+
+/*
+** Convert from ascii to binary encoding of an item.
+*/
+extern SECStatus ATOB_ConvertAsciiToItem(SECItem *binary_item, char *ascii);
+
+/*
+** Convert from binary encoding of an item to ascii.
+*/
+extern char *BTOA_ConvertItemToAscii(SECItem *binary_item);
+
+SEC_END_PROTOS
+
+#endif /* _BASE64_H_ */
diff --git a/security/nss/lib/util/ciferfam.h b/security/nss/lib/util/ciferfam.h
new file mode 100644
index 000000000..74b6adaee
--- /dev/null
+++ b/security/nss/lib/util/ciferfam.h
@@ -0,0 +1,92 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * ciferfam.h - cipher familie IDs used for configuring ciphers for export
+ * control
+ *
+ * $Id$
+ */
+
+#ifndef _CIFERFAM_H_
+#define _CIFERFAM_H_
+
+#include "utilrename.h"
+/* Cipher Suite "Families" */
+#define CIPHER_FAMILY_PKCS12 "PKCS12"
+#define CIPHER_FAMILY_SMIME "SMIME"
+#define CIPHER_FAMILY_SSL2 "SSLv2"
+#define CIPHER_FAMILY_SSL3 "SSLv3"
+#define CIPHER_FAMILY_SSL "SSL"
+#define CIPHER_FAMILY_ALL ""
+#define CIPHER_FAMILY_UNKNOWN "UNKNOWN"
+
+#define CIPHER_FAMILYID_MASK 0xFFFF0000L
+#define CIPHER_FAMILYID_SSL 0x00000000L
+#define CIPHER_FAMILYID_SMIME 0x00010000L
+#define CIPHER_FAMILYID_PKCS12 0x00020000L
+
+/* SMIME "Cipher Suites" */
+/*
+ * Note that it is assumed that the cipher number itself can be used
+ * as a bit position in a mask, and that mask is currently 32 bits wide.
+ * So, if you want to add a cipher that is greater than 0037, secmime.c
+ * needs to be made smarter at the same time.
+ */
+#define SMIME_RC2_CBC_40 (CIPHER_FAMILYID_SMIME | 0001)
+#define SMIME_RC2_CBC_64 (CIPHER_FAMILYID_SMIME | 0002)
+#define SMIME_RC2_CBC_128 (CIPHER_FAMILYID_SMIME | 0003)
+#define SMIME_DES_CBC_56 (CIPHER_FAMILYID_SMIME | 0011)
+#define SMIME_DES_EDE3_168 (CIPHER_FAMILYID_SMIME | 0012)
+#define SMIME_AES_CBC_128 (CIPHER_FAMILYID_SMIME | 0013)
+#define SMIME_RC5PAD_64_16_40 (CIPHER_FAMILYID_SMIME | 0021)
+#define SMIME_RC5PAD_64_16_64 (CIPHER_FAMILYID_SMIME | 0022)
+#define SMIME_RC5PAD_64_16_128 (CIPHER_FAMILYID_SMIME | 0023)
+#define SMIME_FORTEZZA (CIPHER_FAMILYID_SMIME | 0031)
+
+/* PKCS12 "Cipher Suites" */
+
+#define PKCS12_RC2_CBC_40 (CIPHER_FAMILYID_PKCS12 | 0001)
+#define PKCS12_RC2_CBC_128 (CIPHER_FAMILYID_PKCS12 | 0002)
+#define PKCS12_RC4_40 (CIPHER_FAMILYID_PKCS12 | 0011)
+#define PKCS12_RC4_128 (CIPHER_FAMILYID_PKCS12 | 0012)
+#define PKCS12_DES_56 (CIPHER_FAMILYID_PKCS12 | 0021)
+#define PKCS12_DES_EDE3_168 (CIPHER_FAMILYID_PKCS12 | 0022)
+
+/* SMIME version numbers are negative, to avoid colliding with SSL versions */
+#define SMIME_LIBRARY_VERSION_1_0 -0x0100
+
+#endif /* _CIFERFAM_H_ */
diff --git a/security/nss/lib/util/config.mk b/security/nss/lib/util/config.mk
new file mode 100644
index 000000000..b51f3db58
--- /dev/null
+++ b/security/nss/lib/util/config.mk
@@ -0,0 +1,104 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is the Netscape security libraries.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1994-2000
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+#
+# Override TARGETS variable so that only static libraries
+# are specifed as dependencies within rules.mk.
+#
+
+# can't do this in manifest.mn because OS_TARGET isn't defined there.
+ifeq (,$(filter-out WIN%,$(OS_TARGET)))
+
+# don't want the 32 in the shared library name
+SHARED_LIBRARY = $(OBJDIR)/$(DLL_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION).$(DLL_SUFFIX)
+IMPORT_LIBRARY = $(OBJDIR)/$(IMPORT_LIB_PREFIX)$(LIBRARY_NAME)$(LIBRARY_VERSION)$(IMPORT_LIB_SUFFIX)
+
+RES = $(OBJDIR)/$(LIBRARY_NAME).res
+RESNAME = $(LIBRARY_NAME).rc
+
+ifdef NS_USE_GCC
+EXTRA_SHARED_LIBS += \
+ -L$(DIST)/lib \
+ -L$(NSPR_LIB_DIR) \
+ -lplc4 \
+ -lplds4 \
+ -lnspr4\
+ $(NULL)
+else # ! NS_USE_GCC
+EXTRA_SHARED_LIBS += \
+ $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plc4.lib \
+ $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)plds4.lib \
+ $(NSPR_LIB_DIR)/$(NSPR31_LIB_PREFIX)nspr4.lib \
+ $(NULL)
+endif # NS_USE_GCC
+
+else
+
+# $(PROGRAM) has NO explicit dependencies on $(EXTRA_SHARED_LIBS)
+# $(EXTRA_SHARED_LIBS) come before $(OS_LIBS), except on AIX.
+EXTRA_SHARED_LIBS += \
+ -L$(DIST)/lib \
+ -L$(NSPR_LIB_DIR) \
+ -lplc4 \
+ -lplds4 \
+ -lnspr4 \
+ $(NULL)
+
+endif
+
+ifeq ($(OS_TARGET),SunOS)
+ifeq ($(BUILD_SUN_PKG), 1)
+# The -R '$ORIGIN' linker option instructs this library to search for its
+# dependencies in the same directory where it resides.
+ifeq ($(USE_64), 1)
+MKSHLIB += -R '$$ORIGIN:/usr/lib/mps/secv1/64:/usr/lib/mps/64'
+else
+MKSHLIB += -R '$$ORIGIN:/usr/lib/mps/secv1:/usr/lib/mps'
+endif
+else
+MKSHLIB += -R '$$ORIGIN'
+endif
+endif
+
+ifeq ($(OS_ARCH), HP-UX)
+ifneq ($(OS_TEST), ia64)
+# pa-risc
+ifeq ($(USE_64), 1)
+MKSHLIB += +b '$$ORIGIN'
+endif
+endif
+endif
diff --git a/security/nss/lib/util/derdec.c b/security/nss/lib/util/derdec.c
new file mode 100644
index 000000000..4faa680cf
--- /dev/null
+++ b/security/nss/lib/util/derdec.c
@@ -0,0 +1,221 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "secder.h"
+#include "secerr.h"
+
+static PRUint32
+der_indefinite_length(unsigned char *buf, unsigned char *end)
+{
+ PRUint32 len, ret, dataLen;
+ unsigned char tag, lenCode;
+ int dataLenLen;
+
+ len = 0;
+ while ( 1 ) {
+ if ((buf + 2) > end) {
+ return(0);
+ }
+
+ tag = *buf++;
+ lenCode = *buf++;
+ len += 2;
+
+ if ( ( tag == 0 ) && ( lenCode == 0 ) ) {
+ return(len);
+ }
+
+ if ( lenCode == 0x80 ) { /* indefinite length */
+ ret = der_indefinite_length(buf, end); /* recurse to find length */
+ if (ret == 0)
+ return 0;
+ len += ret;
+ buf += ret;
+ } else { /* definite length */
+ if (lenCode & 0x80) {
+ /* Length of data is in multibyte format */
+ dataLenLen = lenCode & 0x7f;
+ switch (dataLenLen) {
+ case 1:
+ dataLen = buf[0];
+ break;
+ case 2:
+ dataLen = (buf[0]<<8)|buf[1];
+ break;
+ case 3:
+ dataLen = ((unsigned long)buf[0]<<16)|(buf[1]<<8)|buf[2];
+ break;
+ case 4:
+ dataLen = ((unsigned long)buf[0]<<24)|
+ ((unsigned long)buf[1]<<16)|(buf[2]<<8)|buf[3];
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ } else {
+ /* Length of data is in single byte */
+ dataLen = lenCode;
+ dataLenLen = 0;
+ }
+
+ /* skip this item */
+ buf = buf + dataLenLen + dataLen;
+ len = len + dataLenLen + dataLen;
+ }
+ }
+}
+
+/*
+** Capture the next thing in the buffer.
+** Returns the length of the header and the length of the contents.
+*/
+static SECStatus
+der_capture(unsigned char *buf, unsigned char *end,
+ int *header_len_p, PRUint32 *contents_len_p)
+{
+ unsigned char *bp;
+ unsigned char whole_tag;
+ PRUint32 contents_len;
+ int tag_number;
+
+ if ((buf + 2) > end) {
+ *header_len_p = 0;
+ *contents_len_p = 0;
+ if (buf == end)
+ return SECSuccess;
+ return SECFailure;
+ }
+
+ bp = buf;
+
+ /* Get tag and verify that it is ok. */
+ whole_tag = *bp++;
+ tag_number = whole_tag & DER_TAGNUM_MASK;
+
+ /*
+ * XXX This code does not (yet) handle the high-tag-number form!
+ */
+ if (tag_number == DER_HIGH_TAG_NUMBER) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+
+ if ((whole_tag & DER_CLASS_MASK) == DER_UNIVERSAL) {
+ /* Check that the universal tag number is one we implement. */
+ switch (tag_number) {
+ case DER_BOOLEAN:
+ case DER_INTEGER:
+ case DER_BIT_STRING:
+ case DER_OCTET_STRING:
+ case DER_NULL:
+ case DER_OBJECT_ID:
+ case DER_SEQUENCE:
+ case DER_SET:
+ case DER_PRINTABLE_STRING:
+ case DER_T61_STRING:
+ case DER_IA5_STRING:
+ case DER_VISIBLE_STRING:
+ case DER_UTC_TIME:
+ case 0: /* end-of-contents tag */
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ }
+
+ /*
+ * Get first byte of length code (might contain entire length, might not).
+ */
+ contents_len = *bp++;
+
+ /*
+ * If the high bit is set, then the length is in multibyte format,
+ * or the thing has an indefinite-length.
+ */
+ if (contents_len & 0x80) {
+ int bytes_of_encoded_len;
+
+ bytes_of_encoded_len = contents_len & 0x7f;
+ contents_len = 0;
+
+ switch (bytes_of_encoded_len) {
+ case 4:
+ contents_len |= *bp++;
+ contents_len <<= 8;
+ /* fallthru */
+ case 3:
+ contents_len |= *bp++;
+ contents_len <<= 8;
+ /* fallthru */
+ case 2:
+ contents_len |= *bp++;
+ contents_len <<= 8;
+ /* fallthru */
+ case 1:
+ contents_len |= *bp++;
+ break;
+
+ case 0:
+ contents_len = der_indefinite_length (bp, end);
+ if (contents_len)
+ break;
+ /* fallthru */
+ default:
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ }
+
+ if ((bp + contents_len) > end) {
+ /* Ran past end of buffer */
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+
+ *header_len_p = bp - buf;
+ *contents_len_p = contents_len;
+
+ return SECSuccess;
+}
+
+SECStatus
+DER_Lengths(SECItem *item, int *header_len_p, PRUint32 *contents_len_p)
+{
+ return(der_capture(item->data, &item->data[item->len], header_len_p,
+ contents_len_p));
+}
diff --git a/security/nss/lib/util/derenc.c b/security/nss/lib/util/derenc.c
new file mode 100644
index 000000000..c14c6a80b
--- /dev/null
+++ b/security/nss/lib/util/derenc.c
@@ -0,0 +1,505 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "secder.h"
+#include "secerr.h"
+
+#if 0
+/*
+ * Generic templates for individual/simple items.
+ */
+
+DERTemplate SECAnyTemplate[] = {
+ { DER_ANY,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECBitStringTemplate[] = {
+ { DER_BIT_STRING,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECBooleanTemplate[] = {
+ { DER_BOOLEAN,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECIA5StringTemplate[] = {
+ { DER_IA5_STRING,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECIntegerTemplate[] = {
+ { DER_INTEGER,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECNullTemplate[] = {
+ { DER_NULL,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECObjectIDTemplate[] = {
+ { DER_OBJECT_ID,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECOctetStringTemplate[] = {
+ { DER_OCTET_STRING,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECPrintableStringTemplate[] = {
+ { DER_PRINTABLE_STRING,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECT61StringTemplate[] = {
+ { DER_T61_STRING,
+ 0, NULL, sizeof(SECItem) }
+};
+
+DERTemplate SECUTCTimeTemplate[] = {
+ { DER_UTC_TIME,
+ 0, NULL, sizeof(SECItem) }
+};
+
+#endif
+
+static int
+header_length(DERTemplate *dtemplate, PRUint32 contents_len)
+{
+ PRUint32 len;
+ unsigned long encode_kind, under_kind;
+ PRBool explicit, optional, universal;
+
+ encode_kind = dtemplate->kind;
+
+ explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
+ optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
+ universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
+ ? PR_TRUE : PR_FALSE;
+
+ PORT_Assert (!(explicit && universal)); /* bad templates */
+
+ if (encode_kind & DER_POINTER) {
+ if (dtemplate->sub != NULL) {
+ under_kind = dtemplate->sub->kind;
+ if (universal) {
+ encode_kind = under_kind;
+ }
+ } else if (universal) {
+ under_kind = encode_kind & ~DER_POINTER;
+ } else {
+ under_kind = dtemplate->arg;
+ }
+ } else if (encode_kind & DER_INLINE) {
+ PORT_Assert (dtemplate->sub != NULL);
+ under_kind = dtemplate->sub->kind;
+ if (universal) {
+ encode_kind = under_kind;
+ }
+ } else if (universal) {
+ under_kind = encode_kind;
+ } else {
+ under_kind = dtemplate->arg;
+ }
+
+ /* This is only used in decoding; it plays no part in encoding. */
+ if (under_kind & DER_DERPTR)
+ return 0;
+
+ /* No header at all for an "empty" optional. */
+ if ((contents_len == 0) && optional)
+ return 0;
+
+ /* And no header for a full DER_ANY. */
+ if (encode_kind & DER_ANY)
+ return 0;
+
+ /*
+ * The common case: one octet for identifier and as many octets
+ * as necessary to hold the content length.
+ */
+ len = 1 + DER_LengthLength(contents_len);
+
+ /* Account for the explicit wrapper, if necessary. */
+ if (explicit) {
+#if 0 /*
+ * Well, I was trying to do something useful, but these
+ * assertions are too restrictive on valid templates.
+ * I wanted to make sure that the top-level "kind" of
+ * a template does not also specify DER_EXPLICIT, which
+ * should only modify a component field. Maybe later
+ * I can figure out a better way to detect such a problem,
+ * but for now I must remove these checks altogether.
+ */
+ /*
+ * This modifier applies only to components of a set or sequence;
+ * it should never be used on a set/sequence itself -- confirm.
+ */
+ PORT_Assert (under_kind != DER_SEQUENCE);
+ PORT_Assert (under_kind != DER_SET);
+#endif
+
+ len += 1 + DER_LengthLength(len + contents_len);
+ }
+
+ return len;
+}
+
+
+static PRUint32
+contents_length(DERTemplate *dtemplate, void *src)
+{
+ PRUint32 len;
+ unsigned long encode_kind, under_kind;
+ PRBool universal;
+
+
+ PORT_Assert (src != NULL);
+
+ encode_kind = dtemplate->kind;
+
+ universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
+ ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~DER_OPTIONAL;
+
+ if (encode_kind & DER_POINTER) {
+ src = *(void **)src;
+ if (src == NULL) {
+ return 0;
+ }
+ if (dtemplate->sub != NULL) {
+ dtemplate = dtemplate->sub;
+ under_kind = dtemplate->kind;
+ src = (void *)((char *)src + dtemplate->offset);
+ } else if (universal) {
+ under_kind = encode_kind & ~DER_POINTER;
+ } else {
+ under_kind = dtemplate->arg;
+ }
+ } else if (encode_kind & DER_INLINE) {
+ PORT_Assert (dtemplate->sub != NULL);
+ dtemplate = dtemplate->sub;
+ under_kind = dtemplate->kind;
+ src = (void *)((char *)src + dtemplate->offset);
+ } else if (universal) {
+ under_kind = encode_kind;
+ } else {
+ under_kind = dtemplate->arg;
+ }
+
+ /* Having any of these bits is not expected here... */
+ PORT_Assert ((under_kind & (DER_EXPLICIT | DER_INLINE | DER_OPTIONAL
+ | DER_POINTER | DER_SKIP)) == 0);
+
+ /* This is only used in decoding; it plays no part in encoding. */
+ if (under_kind & DER_DERPTR)
+ return 0;
+
+ if (under_kind & DER_INDEFINITE) {
+ PRUint32 sub_len;
+ void **indp = *(void ***)src;
+
+ if (indp == NULL)
+ return 0;
+
+ len = 0;
+ under_kind &= ~DER_INDEFINITE;
+
+ if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
+ DERTemplate *tmpt = dtemplate->sub;
+ PORT_Assert (tmpt != NULL);
+
+ for (; *indp != NULL; indp++) {
+ void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
+ sub_len = contents_length (tmpt, sub_src);
+ len += sub_len + header_length (tmpt, sub_len);
+ }
+ } else {
+ /*
+ * XXX Lisa is not sure this code (for handling, for example,
+ * DER_INDEFINITE | DER_OCTET_STRING) is right.
+ */
+ for (; *indp != NULL; indp++) {
+ SECItem *item = (SECItem *)(*indp);
+ sub_len = item->len;
+ if (under_kind == DER_BIT_STRING) {
+ sub_len = (sub_len + 7) >> 3;
+ /* bit string contents involve an extra octet */
+ if (sub_len)
+ sub_len++;
+ }
+ if (under_kind != DER_ANY)
+ len += 1 + DER_LengthLength (sub_len);
+ }
+ }
+
+ return len;
+ }
+
+ switch (under_kind) {
+ case DER_SEQUENCE:
+ case DER_SET:
+ {
+ DERTemplate *tmpt;
+ void *sub_src;
+ PRUint32 sub_len;
+
+ len = 0;
+ for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
+ sub_src = (void *)((char *)src + tmpt->offset);
+ sub_len = contents_length (tmpt, sub_src);
+ len += sub_len + header_length (tmpt, sub_len);
+ }
+ }
+ break;
+
+ case DER_BIT_STRING:
+ len = (((SECItem *)src)->len + 7) >> 3;
+ /* bit string contents involve an extra octet */
+ if (len)
+ len++;
+ break;
+
+ default:
+ len = ((SECItem *)src)->len;
+ break;
+ }
+
+ return len;
+}
+
+
+static unsigned char *
+der_encode(unsigned char *buf, DERTemplate *dtemplate, void *src)
+{
+ int header_len;
+ PRUint32 contents_len;
+ unsigned long encode_kind, under_kind;
+ PRBool explicit, optional, universal;
+
+
+ /*
+ * First figure out how long the encoding will be. Do this by
+ * traversing the template from top to bottom and accumulating
+ * the length of each leaf item.
+ */
+ contents_len = contents_length (dtemplate, src);
+ header_len = header_length (dtemplate, contents_len);
+
+ /*
+ * Enough smarts was involved already, so that if both the
+ * header and the contents have a length of zero, then we
+ * are not doing any encoding for this element.
+ */
+ if (header_len == 0 && contents_len == 0)
+ return buf;
+
+ encode_kind = dtemplate->kind;
+
+ explicit = (encode_kind & DER_EXPLICIT) ? PR_TRUE : PR_FALSE;
+ optional = (encode_kind & DER_OPTIONAL) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~DER_OPTIONAL;
+ universal = ((encode_kind & DER_CLASS_MASK) == DER_UNIVERSAL)
+ ? PR_TRUE : PR_FALSE;
+
+ if (encode_kind & DER_POINTER) {
+ if (contents_len) {
+ src = *(void **)src;
+ PORT_Assert (src != NULL);
+ }
+ if (dtemplate->sub != NULL) {
+ dtemplate = dtemplate->sub;
+ under_kind = dtemplate->kind;
+ if (universal) {
+ encode_kind = under_kind;
+ }
+ src = (void *)((char *)src + dtemplate->offset);
+ } else if (universal) {
+ under_kind = encode_kind & ~DER_POINTER;
+ } else {
+ under_kind = dtemplate->arg;
+ }
+ } else if (encode_kind & DER_INLINE) {
+ dtemplate = dtemplate->sub;
+ under_kind = dtemplate->kind;
+ if (universal) {
+ encode_kind = under_kind;
+ }
+ src = (void *)((char *)src + dtemplate->offset);
+ } else if (universal) {
+ under_kind = encode_kind;
+ } else {
+ under_kind = dtemplate->arg;
+ }
+
+ if (explicit) {
+ buf = DER_StoreHeader (buf, encode_kind,
+ (1 + DER_LengthLength(contents_len)
+ + contents_len));
+ encode_kind = under_kind;
+ }
+
+ if ((encode_kind & DER_ANY) == 0) { /* DER_ANY already contains header */
+ buf = DER_StoreHeader (buf, encode_kind, contents_len);
+ }
+
+ /* If no real contents to encode, then we are done. */
+ if (contents_len == 0)
+ return buf;
+
+ if (under_kind & DER_INDEFINITE) {
+ void **indp;
+
+ indp = *(void ***)src;
+ PORT_Assert (indp != NULL);
+
+ under_kind &= ~DER_INDEFINITE;
+ if (under_kind == DER_SET || under_kind == DER_SEQUENCE) {
+ DERTemplate *tmpt = dtemplate->sub;
+ PORT_Assert (tmpt != NULL);
+ for (; *indp != NULL; indp++) {
+ void *sub_src = (void *)((char *)(*indp) + tmpt->offset);
+ buf = der_encode (buf, tmpt, sub_src);
+ }
+ } else {
+ for (; *indp != NULL; indp++) {
+ SECItem *item;
+ int sub_len;
+
+ item = (SECItem *)(*indp);
+ sub_len = item->len;
+ if (under_kind == DER_BIT_STRING) {
+ if (sub_len) {
+ int rem;
+
+ sub_len = (sub_len + 7) >> 3;
+ buf = DER_StoreHeader (buf, under_kind, sub_len + 1);
+ rem = (sub_len << 3) - item->len;
+ *buf++ = rem; /* remaining bits */
+ } else {
+ buf = DER_StoreHeader (buf, under_kind, 0);
+ }
+ } else if (under_kind != DER_ANY) {
+ buf = DER_StoreHeader (buf, under_kind, sub_len);
+ }
+ PORT_Memcpy (buf, item->data, sub_len);
+ buf += sub_len;
+ }
+ }
+ return buf;
+ }
+
+ switch (under_kind) {
+ case DER_SEQUENCE:
+ case DER_SET:
+ {
+ DERTemplate *tmpt;
+ void *sub_src;
+
+ for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) {
+ sub_src = (void *)((char *)src + tmpt->offset);
+ buf = der_encode (buf, tmpt, sub_src);
+ }
+ }
+ break;
+
+ case DER_BIT_STRING:
+ {
+ SECItem *item;
+ int rem;
+
+ /*
+ * The contents length includes our extra octet; subtract
+ * it off so we just have the real string length there.
+ */
+ contents_len--;
+ item = (SECItem *)src;
+ PORT_Assert (contents_len == ((item->len + 7) >> 3));
+ rem = (contents_len << 3) - item->len;
+ *buf++ = rem; /* remaining bits */
+ PORT_Memcpy (buf, item->data, contents_len);
+ buf += contents_len;
+ }
+ break;
+
+ default:
+ {
+ SECItem *item;
+
+ item = (SECItem *)src;
+ PORT_Assert (contents_len == item->len);
+ PORT_Memcpy (buf, item->data, contents_len);
+ buf += contents_len;
+ }
+ break;
+ }
+
+ return buf;
+}
+
+
+SECStatus
+DER_Encode(PRArenaPool *arena, SECItem *dest, DERTemplate *dtemplate, void *src)
+{
+ unsigned int contents_len, header_len;
+
+ src = (void **)((char *)src + dtemplate->offset);
+
+ /*
+ * First figure out how long the encoding will be. Do this by
+ * traversing the template from top to bottom and accumulating
+ * the length of each leaf item.
+ */
+ contents_len = contents_length (dtemplate, src);
+ header_len = header_length (dtemplate, contents_len);
+
+ dest->len = contents_len + header_len;
+
+ /* Allocate storage to hold the encoding */
+ dest->data = (unsigned char*) PORT_ArenaAlloc(arena, dest->len);
+ if (dest->data == NULL) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return SECFailure;
+ }
+
+ /* Now encode into the buffer */
+ (void) der_encode (dest->data, dtemplate, src);
+
+ return SECSuccess;
+}
diff --git a/security/nss/lib/util/dersubr.c b/security/nss/lib/util/dersubr.c
new file mode 100644
index 000000000..3aa0db8f1
--- /dev/null
+++ b/security/nss/lib/util/dersubr.c
@@ -0,0 +1,266 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "secder.h"
+#include <limits.h>
+#include "secerr.h"
+
+int
+DER_LengthLength(PRUint32 len)
+{
+ if (len > 127) {
+ if (len > 255) {
+ if (len > 65535L) {
+ if (len > 16777215L) {
+ return 5;
+ } else {
+ return 4;
+ }
+ } else {
+ return 3;
+ }
+ } else {
+ return 2;
+ }
+ } else {
+ return 1;
+ }
+}
+
+unsigned char *
+DER_StoreHeader(unsigned char *buf, unsigned int code, PRUint32 len)
+{
+ unsigned char b[4];
+
+ b[0] = (unsigned char)(len >> 24);
+ b[1] = (unsigned char)(len >> 16);
+ b[2] = (unsigned char)(len >> 8);
+ b[3] = (unsigned char)len;
+ if ((code & DER_TAGNUM_MASK) == DER_SET
+ || (code & DER_TAGNUM_MASK) == DER_SEQUENCE)
+ code |= DER_CONSTRUCTED;
+ *buf++ = code;
+ if (len > 127) {
+ if (len > 255) {
+ if (len > 65535) {
+ if (len > 16777215) {
+ *buf++ = 0x84;
+ *buf++ = b[0];
+ *buf++ = b[1];
+ *buf++ = b[2];
+ *buf++ = b[3];
+ } else {
+ *buf++ = 0x83;
+ *buf++ = b[1];
+ *buf++ = b[2];
+ *buf++ = b[3];
+ }
+ } else {
+ *buf++ = 0x82;
+ *buf++ = b[2];
+ *buf++ = b[3];
+ }
+ } else {
+ *buf++ = 0x81;
+ *buf++ = b[3];
+ }
+ } else {
+ *buf++ = b[3];
+ }
+ return buf;
+}
+
+/*
+ * XXX This should be rewritten, generalized, to take a long instead
+ * of a PRInt32.
+ */
+SECStatus
+DER_SetInteger(PRArenaPool *arena, SECItem *it, PRInt32 i)
+{
+ unsigned char bb[4];
+ unsigned len;
+
+ bb[0] = (unsigned char) (i >> 24);
+ bb[1] = (unsigned char) (i >> 16);
+ bb[2] = (unsigned char) (i >> 8);
+ bb[3] = (unsigned char) (i);
+
+ /*
+ ** Small integers are encoded in a single byte. Larger integers
+ ** require progressively more space.
+ */
+ if (i < -128) {
+ if (i < -32768L) {
+ if (i < -8388608L) {
+ len = 4;
+ } else {
+ len = 3;
+ }
+ } else {
+ len = 2;
+ }
+ } else if (i > 127) {
+ if (i > 32767L) {
+ if (i > 8388607L) {
+ len = 4;
+ } else {
+ len = 3;
+ }
+ } else {
+ len = 2;
+ }
+ } else {
+ len = 1;
+ }
+ it->data = (unsigned char*) PORT_ArenaAlloc(arena, len);
+ if (!it->data) {
+ return SECFailure;
+ }
+ it->len = len;
+ PORT_Memcpy(it->data, bb + (4 - len), len);
+ return SECSuccess;
+}
+
+/*
+ * XXX This should be rewritten, generalized, to take an unsigned long instead
+ * of a PRUint32.
+ */
+SECStatus
+DER_SetUInteger(PRArenaPool *arena, SECItem *it, PRUint32 ui)
+{
+ unsigned char bb[5];
+ int len;
+
+ bb[0] = 0;
+ bb[1] = (unsigned char) (ui >> 24);
+ bb[2] = (unsigned char) (ui >> 16);
+ bb[3] = (unsigned char) (ui >> 8);
+ bb[4] = (unsigned char) (ui);
+
+ /*
+ ** Small integers are encoded in a single byte. Larger integers
+ ** require progressively more space.
+ */
+ if (ui > 0x7f) {
+ if (ui > 0x7fff) {
+ if (ui > 0x7fffffL) {
+ if (ui >= 0x80000000L) {
+ len = 5;
+ } else {
+ len = 4;
+ }
+ } else {
+ len = 3;
+ }
+ } else {
+ len = 2;
+ }
+ } else {
+ len = 1;
+ }
+
+ it->data = (unsigned char *)PORT_ArenaAlloc(arena, len);
+ if (it->data == NULL) {
+ return SECFailure;
+ }
+
+ it->len = len;
+ PORT_Memcpy(it->data, bb + (sizeof(bb) - len), len);
+
+ return SECSuccess;
+}
+
+/*
+** Convert a der encoded *signed* integer into a machine integral value.
+** If an underflow/overflow occurs, sets error code and returns min/max.
+*/
+long
+DER_GetInteger(SECItem *it)
+{
+ long ival = 0;
+ unsigned len = it->len;
+ unsigned char *cp = it->data;
+ unsigned long overflow = 0x1ffUL << (((sizeof(ival) - 1) * 8) - 1);
+ unsigned long ofloinit;
+
+ if (*cp & 0x80)
+ ival = -1L;
+ ofloinit = ival & overflow;
+
+ while (len) {
+ if ((ival & overflow) != ofloinit) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ if (ival < 0) {
+ return LONG_MIN;
+ }
+ return LONG_MAX;
+ }
+ ival = ival << 8;
+ ival |= *cp++;
+ --len;
+ }
+ return ival;
+}
+
+/*
+** Convert a der encoded *unsigned* integer into a machine integral value.
+** If an underflow/overflow occurs, sets error code and returns min/max.
+*/
+unsigned long
+DER_GetUInteger(SECItem *it)
+{
+ unsigned long ival = 0;
+ unsigned len = it->len;
+ unsigned char *cp = it->data;
+ unsigned long overflow = 0xffUL << ((sizeof(ival) - 1) * 8);
+
+ /* Cannot put a negative value into an unsigned container. */
+ if (*cp & 0x80) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return 0;
+ }
+
+ while (len) {
+ if (ival & overflow) {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return ULONG_MAX;
+ }
+ ival = ival << 8;
+ ival |= *cp++;
+ --len;
+ }
+ return ival;
+}
diff --git a/security/nss/lib/util/dertime.c b/security/nss/lib/util/dertime.c
new file mode 100644
index 000000000..0dc3625da
--- /dev/null
+++ b/security/nss/lib/util/dertime.c
@@ -0,0 +1,317 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "prtypes.h"
+#include "prtime.h"
+#include "secder.h"
+#include "prlong.h"
+#include "secerr.h"
+
+#define HIDIGIT(v) (((v) / 10) + '0')
+#define LODIGIT(v) (((v) % 10) + '0')
+
+#define ISDIGIT(dig) (((dig) >= '0') && ((dig) <= '9'))
+#define CAPTURE(var,p,label) \
+{ \
+ if (!ISDIGIT((p)[0]) || !ISDIGIT((p)[1])) goto label; \
+ (var) = ((p)[0] - '0') * 10 + ((p)[1] - '0'); \
+ p += 2; \
+}
+
+static const PRTime January1st1 = (PRTime) LL_INIT(0xff234001U, 0x00d44000U);
+static const PRTime January1st1950 = (PRTime) LL_INIT(0xfffdc1f8U, 0x793da000U);
+static const PRTime January1st2050 = LL_INIT(0x0008f81e, 0x1b098000);
+static const PRTime January1st10000 = LL_INIT(0x0384440c, 0xcc736000);
+
+/* gmttime must contains UTC time in micro-seconds unit */
+SECStatus
+DER_TimeToUTCTimeArena(PRArenaPool* arenaOpt, SECItem *dst, int64 gmttime)
+{
+ PRExplodedTime printableTime;
+ unsigned char *d;
+
+ if ( (gmttime < January1st1950) || (gmttime >= January1st2050) ) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ dst->len = 13;
+ if (arenaOpt) {
+ dst->data = d = (unsigned char*) PORT_ArenaAlloc(arenaOpt, dst->len);
+ } else {
+ dst->data = d = (unsigned char*) PORT_Alloc(dst->len);
+ }
+ dst->type = siUTCTime;
+ if (!d) {
+ return SECFailure;
+ }
+
+ /* Convert an int64 time to a printable format. */
+ PR_ExplodeTime(gmttime, PR_GMTParameters, &printableTime);
+
+ /* The month in UTC time is base one */
+ printableTime.tm_month++;
+
+ /* remove the century since it's added to the tm_year by the
+ PR_ExplodeTime routine, but is not needed for UTC time */
+ printableTime.tm_year %= 100;
+
+ d[0] = HIDIGIT(printableTime.tm_year);
+ d[1] = LODIGIT(printableTime.tm_year);
+ d[2] = HIDIGIT(printableTime.tm_month);
+ d[3] = LODIGIT(printableTime.tm_month);
+ d[4] = HIDIGIT(printableTime.tm_mday);
+ d[5] = LODIGIT(printableTime.tm_mday);
+ d[6] = HIDIGIT(printableTime.tm_hour);
+ d[7] = LODIGIT(printableTime.tm_hour);
+ d[8] = HIDIGIT(printableTime.tm_min);
+ d[9] = LODIGIT(printableTime.tm_min);
+ d[10] = HIDIGIT(printableTime.tm_sec);
+ d[11] = LODIGIT(printableTime.tm_sec);
+ d[12] = 'Z';
+ return SECSuccess;
+}
+
+SECStatus
+DER_TimeToUTCTime(SECItem *dst, int64 gmttime)
+{
+ return DER_TimeToUTCTimeArena(NULL, dst, gmttime);
+}
+
+static SECStatus /* forward */
+der_TimeStringToTime(PRTime *dst, const char * string, int generalized);
+
+#define GEN_STRING 2 /* TimeString is a GeneralizedTime */
+#define UTC_STRING 0 /* TimeString is a UTCTime */
+
+/* The caller of DER_AsciiToItem MUST ENSURE that either
+** a) "string" points to a null-terminated ASCII string, or
+** b) "string" points to a buffer containing a valid UTCTime,
+** whether null terminated or not, or
+** c) "string" contains at least 19 characters, with or without null char.
+** otherwise, this function may UMR and/or crash.
+** It suffices to ensure that the input "string" is at least 17 bytes long.
+*/
+SECStatus
+DER_AsciiToTime(int64 *dst, const char *string)
+{
+ return der_TimeStringToTime(dst, string, UTC_STRING);
+}
+
+SECStatus
+DER_UTCTimeToTime(int64 *dst, const SECItem *time)
+{
+ /* Minimum valid UTCTime is yymmddhhmmZ which is 11 bytes.
+ ** Maximum valid UTCTime is yymmddhhmmss+0000 which is 17 bytes.
+ ** 20 should be large enough for all valid encoded times.
+ */
+ int len;
+ char localBuf[20];
+
+ if (!time || !time->data || time->len < 11) {
+ PORT_SetError(SEC_ERROR_INVALID_TIME);
+ return SECFailure;
+ }
+
+ len = PR_MIN(time->len, sizeof localBuf);
+ memcpy(localBuf, time->data, len);
+ while (len < sizeof localBuf) {
+ localBuf[len++] = '\0';
+ }
+
+ return der_TimeStringToTime(dst, localBuf, UTC_STRING);
+}
+
+/*
+ gmttime must contains UTC time in micro-seconds unit.
+ Note: the caller should make sure that Generalized time
+ should only be used for certifiate validities after the
+ year 2049. Otherwise, UTC time should be used. This routine
+ does not check this case, since it can be used to encode
+ certificate extension, which does not have this restriction.
+ */
+SECStatus
+DER_TimeToGeneralizedTimeArena(PRArenaPool* arenaOpt, SECItem *dst, int64 gmttime)
+{
+ PRExplodedTime printableTime;
+ unsigned char *d;
+
+ if ( (gmttime<January1st1) || (gmttime>=January1st10000) ) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ dst->len = 15;
+ if (arenaOpt) {
+ dst->data = d = (unsigned char*) PORT_ArenaAlloc(arenaOpt, dst->len);
+ } else {
+ dst->data = d = (unsigned char*) PORT_Alloc(dst->len);
+ }
+ dst->type = siGeneralizedTime;
+ if (!d) {
+ return SECFailure;
+ }
+
+ /* Convert an int64 time to a printable format. */
+ PR_ExplodeTime(gmttime, PR_GMTParameters, &printableTime);
+
+ /* The month in Generalized time is base one */
+ printableTime.tm_month++;
+
+ d[0] = (printableTime.tm_year /1000) + '0';
+ d[1] = ((printableTime.tm_year % 1000) / 100) + '0';
+ d[2] = ((printableTime.tm_year % 100) / 10) + '0';
+ d[3] = (printableTime.tm_year % 10) + '0';
+ d[4] = HIDIGIT(printableTime.tm_month);
+ d[5] = LODIGIT(printableTime.tm_month);
+ d[6] = HIDIGIT(printableTime.tm_mday);
+ d[7] = LODIGIT(printableTime.tm_mday);
+ d[8] = HIDIGIT(printableTime.tm_hour);
+ d[9] = LODIGIT(printableTime.tm_hour);
+ d[10] = HIDIGIT(printableTime.tm_min);
+ d[11] = LODIGIT(printableTime.tm_min);
+ d[12] = HIDIGIT(printableTime.tm_sec);
+ d[13] = LODIGIT(printableTime.tm_sec);
+ d[14] = 'Z';
+ return SECSuccess;
+}
+
+SECStatus
+DER_TimeToGeneralizedTime(SECItem *dst, int64 gmttime)
+{
+ return DER_TimeToGeneralizedTimeArena(NULL, dst, gmttime);
+}
+
+
+SECStatus
+DER_GeneralizedTimeToTime(int64 *dst, const SECItem *time)
+{
+ /* Minimum valid GeneralizedTime is ccyymmddhhmmZ which is 13 bytes.
+ ** Maximum valid GeneralizedTime is ccyymmddhhmmss+0000 which is 19 bytes.
+ ** 20 should be large enough for all valid encoded times.
+ */
+ int len;
+ char localBuf[20];
+
+ if (!time || !time->data || time->len < 13) {
+ PORT_SetError(SEC_ERROR_INVALID_TIME);
+ return SECFailure;
+ }
+
+ len = PR_MIN(time->len, sizeof localBuf);
+ memcpy(localBuf, time->data, len);
+ while (len < sizeof localBuf) {
+ localBuf[len++] = '\0';
+ }
+
+ return der_TimeStringToTime(dst, localBuf, GEN_STRING);
+}
+
+static SECStatus
+der_TimeStringToTime(PRTime *dst, const char * string, int generalized)
+{
+ PRExplodedTime genTime;
+ long hourOff = 0, minOff = 0;
+ uint16 century;
+ char signum;
+
+ if (string == NULL || dst == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /* Verify time is formatted properly and capture information */
+ memset(&genTime, 0, sizeof genTime);
+
+ if (generalized == UTC_STRING) {
+ CAPTURE(genTime.tm_year, string, loser);
+ century = (genTime.tm_year < 50) ? 20 : 19;
+ } else {
+ CAPTURE(century, string, loser);
+ CAPTURE(genTime.tm_year, string, loser);
+ }
+ genTime.tm_year += century * 100;
+
+ CAPTURE(genTime.tm_month, string, loser);
+ if ((genTime.tm_month == 0) || (genTime.tm_month > 12))
+ goto loser;
+
+ /* NSPR month base is 0 */
+ --genTime.tm_month;
+
+ CAPTURE(genTime.tm_mday, string, loser);
+ if ((genTime.tm_mday == 0) || (genTime.tm_mday > 31))
+ goto loser;
+
+ CAPTURE(genTime.tm_hour, string, loser);
+ if (genTime.tm_hour > 23)
+ goto loser;
+
+ CAPTURE(genTime.tm_min, string, loser);
+ if (genTime.tm_min > 59)
+ goto loser;
+
+ if (ISDIGIT(string[0])) {
+ CAPTURE(genTime.tm_sec, string, loser);
+ if (genTime.tm_sec > 59)
+ goto loser;
+ }
+ signum = *string++;
+ if (signum == '+' || signum == '-') {
+ CAPTURE(hourOff, string, loser);
+ if (hourOff > 23)
+ goto loser;
+ CAPTURE(minOff, string, loser);
+ if (minOff > 59)
+ goto loser;
+ if (signum == '-') {
+ hourOff = -hourOff;
+ minOff = -minOff;
+ }
+ } else if (signum != 'Z') {
+ goto loser;
+ }
+
+ /* Convert the GMT offset to seconds and save it in genTime
+ * for the implode time call.
+ */
+ genTime.tm_params.tp_gmt_offset = (PRInt32)((hourOff * 60L + minOff) * 60L);
+ *dst = PR_ImplodeTime(&genTime);
+ return SECSuccess;
+
+loser:
+ PORT_SetError(SEC_ERROR_INVALID_TIME);
+ return SECFailure;
+}
diff --git a/security/nss/lib/util/manifest.mn b/security/nss/lib/util/manifest.mn
new file mode 100644
index 000000000..3b332529d
--- /dev/null
+++ b/security/nss/lib/util/manifest.mn
@@ -0,0 +1,105 @@
+#
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#
+# The Original Code is the Netscape security libraries.
+#
+# The Initial Developer of the Original Code is
+# Netscape Communications Corporation.
+# Portions created by the Initial Developer are Copyright (C) 1994-2000
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+CORE_DEPTH = ../../..
+
+EXPORTS = \
+ base64.h \
+ ciferfam.h \
+ nssb64.h \
+ nssb64t.h \
+ nsslocks.h \
+ nssilock.h \
+ nssilckt.h \
+ nssrwlk.h \
+ nssrwlkt.h \
+ portreg.h \
+ secasn1.h \
+ secasn1t.h \
+ seccomon.h \
+ secder.h \
+ secdert.h \
+ secdig.h \
+ secdigt.h \
+ secitem.h \
+ secoid.h \
+ secoidt.h \
+ secport.h \
+ secerr.h \
+ utilrename.h \
+ watcomfx.h \
+ $(NULL)
+
+PRIVATE_EXPORTS = \
+ templates.c \
+ $(NULL)
+
+CSRCS = \
+ quickder.c \
+ secdig.c \
+ derdec.c \
+ derenc.c \
+ dersubr.c \
+ dertime.c \
+ nssb64d.c \
+ nssb64e.c \
+ nssrwlk.c \
+ nssilock.c \
+ oidstring.c \
+ portreg.c \
+ secalgid.c \
+ secasn1d.c \
+ secasn1e.c \
+ secasn1u.c \
+ secitem.c \
+ secoid.c \
+ sectime.c \
+ secport.c \
+ secinit.c \
+ templates.c \
+ utf8.c \
+ $(NULL)
+
+MODULE = nss
+
+# don't duplicate module name in REQUIRES
+MAPFILE = $(OBJDIR)/nssutil.def
+
+LIBRARY_NAME = nssutil
+LIBRARY_VERSION = 3
+
+# This part of the code, including all sub-dirs, can be optimized for size
+export ALLOW_OPT_CODE_SIZE = 1
diff --git a/security/nss/lib/util/nssb64.h b/security/nss/lib/util/nssb64.h
new file mode 100644
index 000000000..0b9d4adf2
--- /dev/null
+++ b/security/nss/lib/util/nssb64.h
@@ -0,0 +1,128 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Public prototypes for base64 encoding/decoding.
+ *
+ * $Id$
+ */
+#ifndef _NSSB64_H_
+#define _NSSB64_H_
+
+#include "utilrename.h"
+#include "seccomon.h"
+#include "nssb64t.h"
+
+SEC_BEGIN_PROTOS
+
+/*
+ * Functions to start a base64 decoding/encoding context.
+ */
+
+extern NSSBase64Decoder *
+NSSBase64Decoder_Create (PRInt32 (*output_fn) (void *, const unsigned char *,
+ PRInt32),
+ void *output_arg);
+
+extern NSSBase64Encoder *
+NSSBase64Encoder_Create (PRInt32 (*output_fn) (void *, const char *, PRInt32),
+ void *output_arg);
+
+/*
+ * Push data through the decoder/encoder, causing the output_fn (provided
+ * to Create) to be called with the decoded/encoded data.
+ */
+
+extern SECStatus
+NSSBase64Decoder_Update (NSSBase64Decoder *data, const char *buffer,
+ PRUint32 size);
+
+extern SECStatus
+NSSBase64Encoder_Update (NSSBase64Encoder *data, const unsigned char *buffer,
+ PRUint32 size);
+
+/*
+ * When you're done processing, call this to close the context.
+ * If "abort_p" is false, then calling this may cause the output_fn
+ * to be called one last time (as the last buffered data is flushed out).
+ */
+
+extern SECStatus
+NSSBase64Decoder_Destroy (NSSBase64Decoder *data, PRBool abort_p);
+
+extern SECStatus
+NSSBase64Encoder_Destroy (NSSBase64Encoder *data, PRBool abort_p);
+
+/*
+ * Perform base64 decoding from an ascii string "inStr" to an Item.
+ * The length of the input must be provided as "inLen". The Item
+ * may be provided (as "outItemOpt"); you can also pass in a NULL
+ * and the Item will be allocated for you.
+ *
+ * In any case, the data within the Item will be allocated for you.
+ * All allocation will happen out of the passed-in "arenaOpt", if non-NULL.
+ * If "arenaOpt" is NULL, standard allocation (heap) will be used and
+ * you will want to free the result via SECITEM_FreeItem.
+ *
+ * Return value is NULL on error, the Item (allocated or provided) otherwise.
+ */
+extern SECItem *
+NSSBase64_DecodeBuffer (PLArenaPool *arenaOpt, SECItem *outItemOpt,
+ const char *inStr, unsigned int inLen);
+
+/*
+ * Perform base64 encoding of binary data "inItem" to an ascii string.
+ * The output buffer may be provided (as "outStrOpt"); you can also pass
+ * in a NULL and the buffer will be allocated for you. The result will
+ * be null-terminated, and if the buffer is provided, "maxOutLen" must
+ * specify the maximum length of the buffer and will be checked to
+ * supply sufficient space space for the encoded result. (If "outStrOpt"
+ * is NULL, "maxOutLen" is ignored.)
+ *
+ * If "outStrOpt" is NULL, allocation will happen out of the passed-in
+ * "arenaOpt", if *it* is non-NULL, otherwise standard allocation (heap)
+ * will be used.
+ *
+ * Return value is NULL on error, the output buffer (allocated or provided)
+ * otherwise.
+ */
+extern char *
+NSSBase64_EncodeItem (PLArenaPool *arenaOpt, char *outStrOpt,
+ unsigned int maxOutLen, SECItem *inItem);
+
+SEC_END_PROTOS
+
+#endif /* _NSSB64_H_ */
diff --git a/security/nss/lib/util/nssb64d.c b/security/nss/lib/util/nssb64d.c
new file mode 100644
index 000000000..42b1ca684
--- /dev/null
+++ b/security/nss/lib/util/nssb64d.c
@@ -0,0 +1,864 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Base64 decoding (ascii to binary).
+ *
+ * $Id$
+ */
+
+#include "nssb64.h"
+#include "nspr.h"
+#include "secitem.h"
+#include "secerr.h"
+
+/*
+ * XXX We want this basic support to go into NSPR (the PL part).
+ * Until that can happen, the PL interface is going to be kept entirely
+ * internal here -- all static functions and opaque data structures.
+ * When someone can get it moved over into NSPR, that should be done:
+ * - giving everything names that are accepted by the NSPR module owners
+ * (though I tried to choose ones that would work without modification)
+ * - exporting the functions (remove static declarations and add
+ * to nssutil.def as necessary)
+ * - put prototypes into appropriate header file (probably replacing
+ * the entire current lib/libc/include/plbase64.h in NSPR)
+ * along with a typedef for the context structure (which should be
+ * kept opaque -- definition in the source file only, but typedef
+ * ala "typedef struct PLBase64FooStr PLBase64Foo;" in header file)
+ * - modify anything else as necessary to conform to NSPR required style
+ * (I looked but found no formatting guide to follow)
+ *
+ * You will want to move over everything from here down to the comment
+ * which says "XXX End of base64 decoding code to be moved into NSPR",
+ * into a new file in NSPR.
+ */
+
+/*
+ **************************************************************
+ * XXX Beginning of base64 decoding code to be moved into NSPR.
+ */
+
+/*
+ * This typedef would belong in the NSPR header file (i.e. plbase64.h).
+ */
+typedef struct PLBase64DecoderStr PLBase64Decoder;
+
+/*
+ * The following implementation of base64 decoding was based on code
+ * found in libmime (specifically, in mimeenc.c). It has been adapted to
+ * use PR types and naming as well as to provide other necessary semantics
+ * (like buffer-in/buffer-out in addition to "streaming" without undue
+ * performance hit of extra copying if you made the buffer versions
+ * use the output_fn). It also incorporates some aspects of the current
+ * NSPR base64 decoding code. As such, you may find similarities to
+ * both of those implementations. I tried to use names that reflected
+ * the original code when possible. For this reason you may find some
+ * inconsistencies -- libmime used lots of "in" and "out" whereas the
+ * NSPR version uses "src" and "dest"; sometimes I changed one to the other
+ * and sometimes I left them when I thought the subroutines were at least
+ * self-consistent.
+ */
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * Opaque object used by the decoder to store state.
+ */
+struct PLBase64DecoderStr {
+ /* Current token (or portion, if token_size < 4) being decoded. */
+ unsigned char token[4];
+ int token_size;
+
+ /*
+ * Where to write the decoded data (used when streaming, not when
+ * doing all in-memory (buffer) operations).
+ *
+ * Note that this definition is chosen to be compatible with PR_Write.
+ */
+ PRInt32 (*output_fn) (void *output_arg, const unsigned char *buf,
+ PRInt32 size);
+ void *output_arg;
+
+ /*
+ * Where the decoded output goes -- either temporarily (in the streaming
+ * case, staged here before it goes to the output function) or what will
+ * be the entire buffered result for users of the buffer version.
+ */
+ unsigned char *output_buffer;
+ PRUint32 output_buflen; /* the total length of allocated buffer */
+ PRUint32 output_length; /* the length that is currently populated */
+};
+
+PR_END_EXTERN_C
+
+
+/*
+ * Table to convert an ascii "code" to its corresponding binary value.
+ * For ease of use, the binary values in the table are the actual values
+ * PLUS ONE. This is so that the special value of zero can denote an
+ * invalid mapping; that was much easier than trying to fill in the other
+ * values with some value other than zero, and to check for it.
+ * Just remember to SUBTRACT ONE when using the value retrieved.
+ */
+static unsigned char base64_codetovaluep1[256] = {
+/* 0: */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* 8: */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* 16: */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* 24: */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* 32: */ 0, 0, 0, 0, 0, 0, 0, 0,
+/* 40: */ 0, 0, 0, 63, 0, 0, 0, 64,
+/* 48: */ 53, 54, 55, 56, 57, 58, 59, 60,
+/* 56: */ 61, 62, 0, 0, 0, 0, 0, 0,
+/* 64: */ 0, 1, 2, 3, 4, 5, 6, 7,
+/* 72: */ 8, 9, 10, 11, 12, 13, 14, 15,
+/* 80: */ 16, 17, 18, 19, 20, 21, 22, 23,
+/* 88: */ 24, 25, 26, 0, 0, 0, 0, 0,
+/* 96: */ 0, 27, 28, 29, 30, 31, 32, 33,
+/* 104: */ 34, 35, 36, 37, 38, 39, 40, 41,
+/* 112: */ 42, 43, 44, 45, 46, 47, 48, 49,
+/* 120: */ 50, 51, 52, 0, 0, 0, 0, 0,
+/* 128: */ 0, 0, 0, 0, 0, 0, 0, 0
+/* and rest are all zero as well */
+};
+
+#define B64_PAD '='
+
+
+/*
+ * Reads 4; writes 3 (known, or expected, to have no trailing padding).
+ * Returns bytes written; -1 on error (unexpected character).
+ */
+static int
+pl_base64_decode_4to3 (const unsigned char *in, unsigned char *out)
+{
+ int j;
+ PRUint32 num = 0;
+ unsigned char bits;
+
+ for (j = 0; j < 4; j++) {
+ bits = base64_codetovaluep1[in[j]];
+ if (bits == 0)
+ return -1;
+ num = (num << 6) | (bits - 1);
+ }
+
+ out[0] = (unsigned char) (num >> 16);
+ out[1] = (unsigned char) ((num >> 8) & 0xFF);
+ out[2] = (unsigned char) (num & 0xFF);
+
+ return 3;
+}
+
+/*
+ * Reads 3; writes 2 (caller already confirmed EOF or trailing padding).
+ * Returns bytes written; -1 on error (unexpected character).
+ */
+static int
+pl_base64_decode_3to2 (const unsigned char *in, unsigned char *out)
+{
+ PRUint32 num = 0;
+ unsigned char bits1, bits2, bits3;
+
+ bits1 = base64_codetovaluep1[in[0]];
+ bits2 = base64_codetovaluep1[in[1]];
+ bits3 = base64_codetovaluep1[in[2]];
+
+ if ((bits1 == 0) || (bits2 == 0) || (bits3 == 0))
+ return -1;
+
+ num = ((PRUint32)(bits1 - 1)) << 10;
+ num |= ((PRUint32)(bits2 - 1)) << 4;
+ num |= ((PRUint32)(bits3 - 1)) >> 2;
+
+ out[0] = (unsigned char) (num >> 8);
+ out[1] = (unsigned char) (num & 0xFF);
+
+ return 2;
+}
+
+/*
+ * Reads 2; writes 1 (caller already confirmed EOF or trailing padding).
+ * Returns bytes written; -1 on error (unexpected character).
+ */
+static int
+pl_base64_decode_2to1 (const unsigned char *in, unsigned char *out)
+{
+ PRUint32 num = 0;
+ unsigned char bits1, bits2;
+
+ bits1 = base64_codetovaluep1[in[0]];
+ bits2 = base64_codetovaluep1[in[1]];
+
+ if ((bits1 == 0) || (bits2 == 0))
+ return -1;
+
+ num = ((PRUint32)(bits1 - 1)) << 2;
+ num |= ((PRUint32)(bits2 - 1)) >> 4;
+
+ out[0] = (unsigned char) num;
+
+ return 1;
+}
+
+/*
+ * Reads 4; writes 0-3. Returns bytes written or -1 on error.
+ * (Writes less than 3 only at (presumed) EOF.)
+ */
+static int
+pl_base64_decode_token (const unsigned char *in, unsigned char *out)
+{
+ if (in[3] != B64_PAD)
+ return pl_base64_decode_4to3 (in, out);
+
+ if (in[2] == B64_PAD)
+ return pl_base64_decode_2to1 (in, out);
+
+ return pl_base64_decode_3to2 (in, out);
+}
+
+static PRStatus
+pl_base64_decode_buffer (PLBase64Decoder *data, const unsigned char *in,
+ PRUint32 length)
+{
+ unsigned char *out = data->output_buffer;
+ unsigned char *token = data->token;
+ int i, n = 0;
+
+ i = data->token_size;
+ data->token_size = 0;
+
+ while (length > 0) {
+ while (i < 4 && length > 0) {
+ /*
+ * XXX Note that the following simply ignores any unexpected
+ * characters. This is exactly what the original code in
+ * libmime did, and I am leaving it. We certainly want to skip
+ * over whitespace (we must); this does much more than that.
+ * I am not confident changing it, and I don't want to slow
+ * the processing down doing more complicated checking, but
+ * someone else might have different ideas in the future.
+ */
+ if (base64_codetovaluep1[*in] > 0 || *in == B64_PAD)
+ token[i++] = *in;
+ in++;
+ length--;
+ }
+
+ if (i < 4) {
+ /* Didn't get enough for a complete token. */
+ data->token_size = i;
+ break;
+ }
+ i = 0;
+
+ PR_ASSERT((out - data->output_buffer + 3) <= data->output_buflen);
+
+ /*
+ * Assume we are not at the end; the following function only works
+ * for an internal token (no trailing padding characters) but is
+ * faster that way. If it hits an invalid character (padding) it
+ * will return an error; we break out of the loop and try again
+ * calling the routine that will handle a final token.
+ * Note that we intentionally do it this way rather than explicitly
+ * add a check for padding here (because that would just slow down
+ * the normal case) nor do we rely on checking whether we have more
+ * input to process (because that would also slow it down but also
+ * because we want to allow trailing garbage, especially white space
+ * and cannot tell that without read-ahead, also a slow proposition).
+ * Whew. Understand?
+ */
+ n = pl_base64_decode_4to3 (token, out);
+ if (n < 0)
+ break;
+
+ /* Advance "out" by the number of bytes just written to it. */
+ out += n;
+ n = 0;
+ }
+
+ /*
+ * See big comment above, before call to pl_base64_decode_4to3.
+ * Here we check if we error'd out of loop, and allow for the case
+ * that we are processing the last interesting token. If the routine
+ * which should handle padding characters also fails, then we just
+ * have bad input and give up.
+ */
+ if (n < 0) {
+ n = pl_base64_decode_token (token, out);
+ if (n < 0)
+ return PR_FAILURE;
+
+ out += n;
+ }
+
+ /*
+ * As explained above, we can get here with more input remaining, but
+ * it should be all characters we do not care about (i.e. would be
+ * ignored when transferring from "in" to "token" in loop above,
+ * except here we choose to ignore extraneous pad characters, too).
+ * Swallow it, performing that check. If we find more characters that
+ * we would expect to decode, something is wrong.
+ */
+ while (length > 0) {
+ if (base64_codetovaluep1[*in] > 0)
+ return PR_FAILURE;
+ in++;
+ length--;
+ }
+
+ /* Record the length of decoded data we have left in output_buffer. */
+ data->output_length = (PRUint32) (out - data->output_buffer);
+ return PR_SUCCESS;
+}
+
+/*
+ * Flush any remaining buffered characters. Given well-formed input,
+ * this will have nothing to do. If the input was missing the padding
+ * characters at the end, though, there could be 1-3 characters left
+ * behind -- we will tolerate that by adding the padding for them.
+ */
+static PRStatus
+pl_base64_decode_flush (PLBase64Decoder *data)
+{
+ int count;
+
+ /*
+ * If no remaining characters, or all are padding (also not well-formed
+ * input, but again, be tolerant), then nothing more to do. (And, that
+ * is considered successful.)
+ */
+ if (data->token_size == 0 || data->token[0] == B64_PAD)
+ return PR_SUCCESS;
+
+ /*
+ * Assume we have all the interesting input except for some expected
+ * padding characters. Add them and decode the resulting token.
+ */
+ while (data->token_size < 4)
+ data->token[data->token_size++] = B64_PAD;
+
+ data->token_size = 0; /* so a subsequent flush call is a no-op */
+
+ count = pl_base64_decode_token (data->token,
+ data->output_buffer + data->output_length);
+ if (count < 0)
+ return PR_FAILURE;
+
+ /*
+ * If there is an output function, call it with this last bit of data.
+ * Otherwise we are doing all buffered output, and the decoded bytes
+ * are now there, we just need to reflect that in the length.
+ */
+ if (data->output_fn != NULL) {
+ PRInt32 output_result;
+
+ PR_ASSERT(data->output_length == 0);
+ output_result = data->output_fn (data->output_arg,
+ data->output_buffer,
+ (PRInt32) count);
+ if (output_result < 0)
+ return PR_FAILURE;
+ } else {
+ data->output_length += count;
+ }
+
+ return PR_SUCCESS;
+}
+
+
+/*
+ * The maximum space needed to hold the output of the decoder given
+ * input data of length "size".
+ */
+static PRUint32
+PL_Base64MaxDecodedLength (PRUint32 size)
+{
+ return ((size * 3) / 4);
+}
+
+
+/*
+ * A distinct internal creation function for the buffer version to use.
+ * (It does not want to specify an output_fn, and we want the normal
+ * Create function to require that.) If more common initialization
+ * of the decoding context needs to be done, it should be done *here*.
+ */
+static PLBase64Decoder *
+pl_base64_create_decoder (void)
+{
+ return PR_NEWZAP(PLBase64Decoder);
+}
+
+/*
+ * Function to start a base64 decoding context.
+ * An "output_fn" is required; the "output_arg" parameter to that is optional.
+ */
+static PLBase64Decoder *
+PL_CreateBase64Decoder (PRInt32 (*output_fn) (void *, const unsigned char *,
+ PRInt32),
+ void *output_arg)
+{
+ PLBase64Decoder *data;
+
+ if (output_fn == NULL) {
+ PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+ return NULL;
+ }
+
+ data = pl_base64_create_decoder ();
+ if (data != NULL) {
+ data->output_fn = output_fn;
+ data->output_arg = output_arg;
+ }
+ return data;
+}
+
+
+/*
+ * Push data through the decoder, causing the output_fn (provided to Create)
+ * to be called with the decoded data.
+ */
+static PRStatus
+PL_UpdateBase64Decoder (PLBase64Decoder *data, const char *buffer,
+ PRUint32 size)
+{
+ PRUint32 need_length;
+ PRStatus status;
+
+ /* XXX Should we do argument checking only in debug build? */
+ if (data == NULL || buffer == NULL || size == 0) {
+ PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+ return PR_FAILURE;
+ }
+
+ /*
+ * How much space could this update need for decoding?
+ */
+ need_length = PL_Base64MaxDecodedLength (size + data->token_size);
+
+ /*
+ * Make sure we have at least that much. If not, (re-)allocate.
+ */
+ if (need_length > data->output_buflen) {
+ unsigned char *output_buffer = data->output_buffer;
+
+ if (output_buffer != NULL)
+ output_buffer = (unsigned char *) PR_Realloc(output_buffer,
+ need_length);
+ else
+ output_buffer = (unsigned char *) PR_Malloc(need_length);
+
+ if (output_buffer == NULL)
+ return PR_FAILURE;
+
+ data->output_buffer = output_buffer;
+ data->output_buflen = need_length;
+ }
+
+ /* There should not have been any leftover output data in the buffer. */
+ PR_ASSERT(data->output_length == 0);
+ data->output_length = 0;
+
+ status = pl_base64_decode_buffer (data, (const unsigned char *) buffer,
+ size);
+
+ /* Now that we have some decoded data, write it. */
+ if (status == PR_SUCCESS && data->output_length > 0) {
+ PRInt32 output_result;
+
+ PR_ASSERT(data->output_fn != NULL);
+ output_result = data->output_fn (data->output_arg,
+ data->output_buffer,
+ (PRInt32) data->output_length);
+ if (output_result < 0)
+ status = PR_FAILURE;
+ }
+
+ data->output_length = 0;
+ return status;
+}
+
+
+/*
+ * When you're done decoding, call this to free the data. If "abort_p"
+ * is false, then calling this may cause the output_fn to be called
+ * one last time (as the last buffered data is flushed out).
+ */
+static PRStatus
+PL_DestroyBase64Decoder (PLBase64Decoder *data, PRBool abort_p)
+{
+ PRStatus status = PR_SUCCESS;
+
+ /* XXX Should we do argument checking only in debug build? */
+ if (data == NULL) {
+ PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+ return PR_FAILURE;
+ }
+
+ /* Flush out the last few buffered characters. */
+ if (!abort_p)
+ status = pl_base64_decode_flush (data);
+
+ if (data->output_buffer != NULL)
+ PR_Free(data->output_buffer);
+ PR_Free(data);
+
+ return status;
+}
+
+
+/*
+ * Perform base64 decoding from an input buffer to an output buffer.
+ * The output buffer can be provided (as "dest"); you can also pass in
+ * a NULL and this function will allocate a buffer large enough for you,
+ * and return it. If you do provide the output buffer, you must also
+ * provide the maximum length of that buffer (as "maxdestlen").
+ * The actual decoded length of output will be returned to you in
+ * "output_destlen".
+ *
+ * Return value is NULL on error, the output buffer (allocated or provided)
+ * otherwise.
+ */
+static unsigned char *
+PL_Base64DecodeBuffer (const char *src, PRUint32 srclen, unsigned char *dest,
+ PRUint32 maxdestlen, PRUint32 *output_destlen)
+{
+ PRUint32 need_length;
+ unsigned char *output_buffer = NULL;
+ PLBase64Decoder *data = NULL;
+ PRStatus status;
+
+ PR_ASSERT(srclen > 0);
+ if (srclen == 0)
+ return dest;
+
+ /*
+ * How much space could we possibly need for decoding this input?
+ */
+ need_length = PL_Base64MaxDecodedLength (srclen);
+
+ /*
+ * Make sure we have at least that much, if output buffer provided.
+ * If no output buffer provided, then we allocate that much.
+ */
+ if (dest != NULL) {
+ PR_ASSERT(maxdestlen >= need_length);
+ if (maxdestlen < need_length) {
+ PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
+ goto loser;
+ }
+ output_buffer = dest;
+ } else {
+ output_buffer = (unsigned char *) PR_Malloc(need_length);
+ if (output_buffer == NULL)
+ goto loser;
+ maxdestlen = need_length;
+ }
+
+ data = pl_base64_create_decoder();
+ if (data == NULL)
+ goto loser;
+
+ data->output_buflen = maxdestlen;
+ data->output_buffer = output_buffer;
+
+ status = pl_base64_decode_buffer (data, (const unsigned char *) src,
+ srclen);
+
+ /*
+ * We do not wait for Destroy to flush, because Destroy will also
+ * get rid of our decoder context, which we need to look at first!
+ */
+ if (status == PR_SUCCESS)
+ status = pl_base64_decode_flush (data);
+
+ /* Must clear this or Destroy will free it. */
+ data->output_buffer = NULL;
+
+ if (status == PR_SUCCESS) {
+ *output_destlen = data->output_length;
+ status = PL_DestroyBase64Decoder (data, PR_FALSE);
+ data = NULL;
+ if (status == PR_FAILURE)
+ goto loser;
+ return output_buffer;
+ }
+
+loser:
+ if (dest == NULL && output_buffer != NULL)
+ PR_Free(output_buffer);
+ if (data != NULL)
+ (void) PL_DestroyBase64Decoder (data, PR_TRUE);
+ return NULL;
+}
+
+
+/*
+ * XXX End of base64 decoding code to be moved into NSPR.
+ ********************************************************
+ */
+
+/*
+ * This is the beginning of the NSS cover functions. These will
+ * provide the interface we want to expose as NSS-ish. For example,
+ * they will operate on our Items, do any special handling or checking
+ * we want to do, etc.
+ */
+
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * A boring cover structure for now. Perhaps someday it will include
+ * some more interesting fields.
+ */
+struct NSSBase64DecoderStr {
+ PLBase64Decoder *pl_data;
+};
+
+PR_END_EXTERN_C
+
+
+/*
+ * Function to start a base64 decoding context.
+ */
+NSSBase64Decoder *
+NSSBase64Decoder_Create (PRInt32 (*output_fn) (void *, const unsigned char *,
+ PRInt32),
+ void *output_arg)
+{
+ PLBase64Decoder *pl_data;
+ NSSBase64Decoder *nss_data;
+
+ nss_data = PORT_ZNew(NSSBase64Decoder);
+ if (nss_data == NULL)
+ return NULL;
+
+ pl_data = PL_CreateBase64Decoder (output_fn, output_arg);
+ if (pl_data == NULL) {
+ PORT_Free(nss_data);
+ return NULL;
+ }
+
+ nss_data->pl_data = pl_data;
+ return nss_data;
+}
+
+
+/*
+ * Push data through the decoder, causing the output_fn (provided to Create)
+ * to be called with the decoded data.
+ */
+SECStatus
+NSSBase64Decoder_Update (NSSBase64Decoder *data, const char *buffer,
+ PRUint32 size)
+{
+ PRStatus pr_status;
+
+ /* XXX Should we do argument checking only in debug build? */
+ if (data == NULL) {
+ PORT_SetError (SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ pr_status = PL_UpdateBase64Decoder (data->pl_data, buffer, size);
+ if (pr_status == PR_FAILURE)
+ return SECFailure;
+
+ return SECSuccess;
+}
+
+
+/*
+ * When you're done decoding, call this to free the data. If "abort_p"
+ * is false, then calling this may cause the output_fn to be called
+ * one last time (as the last buffered data is flushed out).
+ */
+SECStatus
+NSSBase64Decoder_Destroy (NSSBase64Decoder *data, PRBool abort_p)
+{
+ PRStatus pr_status;
+
+ /* XXX Should we do argument checking only in debug build? */
+ if (data == NULL) {
+ PORT_SetError (SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ pr_status = PL_DestroyBase64Decoder (data->pl_data, abort_p);
+
+ PORT_Free(data);
+
+ if (pr_status == PR_FAILURE)
+ return SECFailure;
+
+ return SECSuccess;
+}
+
+
+/*
+ * Perform base64 decoding from an ascii string "inStr" to an Item.
+ * The length of the input must be provided as "inLen". The Item
+ * may be provided (as "outItemOpt"); you can also pass in a NULL
+ * and the Item will be allocated for you.
+ *
+ * In any case, the data within the Item will be allocated for you.
+ * All allocation will happen out of the passed-in "arenaOpt", if non-NULL.
+ * If "arenaOpt" is NULL, standard allocation (heap) will be used and
+ * you will want to free the result via SECITEM_FreeItem.
+ *
+ * Return value is NULL on error, the Item (allocated or provided) otherwise.
+ */
+SECItem *
+NSSBase64_DecodeBuffer (PRArenaPool *arenaOpt, SECItem *outItemOpt,
+ const char *inStr, unsigned int inLen)
+{
+ SECItem *out_item = outItemOpt;
+ PRUint32 max_out_len = PL_Base64MaxDecodedLength (inLen);
+ PRUint32 out_len;
+ void *mark = NULL;
+ unsigned char *dummy;
+
+ PORT_Assert(outItemOpt == NULL || outItemOpt->data == NULL);
+
+ if (arenaOpt != NULL)
+ mark = PORT_ArenaMark (arenaOpt);
+
+ out_item = SECITEM_AllocItem (arenaOpt, outItemOpt, max_out_len);
+ if (out_item == NULL) {
+ if (arenaOpt != NULL)
+ PORT_ArenaRelease (arenaOpt, mark);
+ return NULL;
+ }
+
+ dummy = PL_Base64DecodeBuffer (inStr, inLen, out_item->data,
+ max_out_len, &out_len);
+ if (dummy == NULL) {
+ if (arenaOpt != NULL) {
+ PORT_ArenaRelease (arenaOpt, mark);
+ if (outItemOpt != NULL) {
+ outItemOpt->data = NULL;
+ outItemOpt->len = 0;
+ }
+ } else {
+ SECITEM_FreeItem (out_item,
+ (outItemOpt == NULL) ? PR_TRUE : PR_FALSE);
+ }
+ return NULL;
+ }
+
+ if (arenaOpt != NULL)
+ PORT_ArenaUnmark (arenaOpt, mark);
+ out_item->len = out_len;
+ return out_item;
+}
+
+
+/*
+ * XXX Everything below is deprecated. If you add new stuff, put it
+ * *above*, not below.
+ */
+
+/*
+ * XXX The following "ATOB" functions are provided for backward compatibility
+ * with current code. They should be considered strongly deprecated.
+ * When we can convert all our code over to using the new NSSBase64Decoder_
+ * functions defined above, we should get rid of these altogether. (Remove
+ * protoypes from base64.h as well -- actually, remove that file completely).
+ * If someone thinks either of these functions provides such a very useful
+ * interface (though, as shown, the same functionality can already be
+ * obtained by calling NSSBase64_DecodeBuffer directly), fine -- but then
+ * that API should be provided with a nice new NSSFoo name and using
+ * appropriate types, etc.
+ */
+
+#include "base64.h"
+
+/*
+** Return an PORT_Alloc'd string which is the base64 decoded version
+** of the input string; set *lenp to the length of the returned data.
+*/
+unsigned char *
+ATOB_AsciiToData(const char *string, unsigned int *lenp)
+{
+ SECItem binary_item, *dummy;
+
+ binary_item.data = NULL;
+ binary_item.len = 0;
+
+ dummy = NSSBase64_DecodeBuffer (NULL, &binary_item, string,
+ (PRUint32) PORT_Strlen(string));
+ if (dummy == NULL)
+ return NULL;
+
+ PORT_Assert(dummy == &binary_item);
+
+ *lenp = dummy->len;
+ return dummy->data;
+}
+
+/*
+** Convert from ascii to binary encoding of an item.
+*/
+SECStatus
+ATOB_ConvertAsciiToItem(SECItem *binary_item, char *ascii)
+{
+ SECItem *dummy;
+
+ if (binary_item == NULL) {
+ PORT_SetError (SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ /*
+ * XXX Would prefer to assert here if data is non-null (actually,
+ * don't need to, just let NSSBase64_DecodeBuffer do it), so as to
+ * to catch unintended memory leaks, but callers are not clean in
+ * this respect so we need to explicitly clear here to avoid the
+ * assert in NSSBase64_DecodeBuffer.
+ */
+ binary_item->data = NULL;
+ binary_item->len = 0;
+
+ dummy = NSSBase64_DecodeBuffer (NULL, binary_item, ascii,
+ (PRUint32) PORT_Strlen(ascii));
+
+ if (dummy == NULL)
+ return SECFailure;
+
+ return SECSuccess;
+}
diff --git a/security/nss/lib/util/nssb64e.c b/security/nss/lib/util/nssb64e.c
new file mode 100644
index 000000000..71cf05373
--- /dev/null
+++ b/security/nss/lib/util/nssb64e.c
@@ -0,0 +1,765 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Base64 encoding (binary to ascii).
+ *
+ * $Id$
+ */
+
+#include "nssb64.h"
+#include "nspr.h"
+#include "secitem.h"
+#include "secerr.h"
+
+/*
+ * XXX See the big comment at the top of nssb64d.c about moving the
+ * bulk of this code over into NSPR (the PL part). It all applies
+ * here but I didn't want to duplicate it, to avoid divergence problems.
+ */
+
+/*
+ **************************************************************
+ * XXX Beginning of base64 encoding code to be moved into NSPR.
+ */
+
+
+struct PLBase64EncodeStateStr {
+ unsigned chunks;
+ unsigned saved;
+ unsigned char buf[3];
+};
+
+/*
+ * This typedef would belong in the NSPR header file (i.e. plbase64.h).
+ */
+typedef struct PLBase64EncoderStr PLBase64Encoder;
+
+/*
+ * The following implementation of base64 encoding was based on code
+ * found in libmime (specifically, in mimeenc.c). It has been adapted to
+ * use PR types and naming as well as to provide other necessary semantics
+ * (like buffer-in/buffer-out in addition to "streaming" without undue
+ * performance hit of extra copying if you made the buffer versions
+ * use the output_fn). It also incorporates some aspects of the current
+ * NSPR base64 encoding code. As such, you may find similarities to
+ * both of those implementations. I tried to use names that reflected
+ * the original code when possible. For this reason you may find some
+ * inconsistencies -- libmime used lots of "in" and "out" whereas the
+ * NSPR version uses "src" and "dest"; sometimes I changed one to the other
+ * and sometimes I left them when I thought the subroutines were at least
+ * self-consistent.
+ */
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * Opaque object used by the encoder to store state.
+ */
+struct PLBase64EncoderStr {
+ /*
+ * The one or two bytes pending. (We need 3 to create a "token",
+ * and hold the leftovers here. in_buffer_count is *only* ever
+ * 0, 1, or 2.
+ */
+ unsigned char in_buffer[2];
+ int in_buffer_count;
+
+ /*
+ * If the caller wants linebreaks added, line_length specifies
+ * where they come out. It must be a multiple of 4; if the caller
+ * provides one that isn't, we round it down to the nearest
+ * multiple of 4.
+ *
+ * The value of current_column counts how many characters have been
+ * added since the last linebreaks (or since the beginning, on the
+ * first line). It is also always a multiple of 4; it is unused when
+ * line_length is 0.
+ */
+ PRUint32 line_length;
+ PRUint32 current_column;
+
+ /*
+ * Where to write the encoded data (used when streaming, not when
+ * doing all in-memory (buffer) operations).
+ *
+ * Note that this definition is chosen to be compatible with PR_Write.
+ */
+ PRInt32 (*output_fn) (void *output_arg, const char *buf, PRInt32 size);
+ void *output_arg;
+
+ /*
+ * Where the encoded output goes -- either temporarily (in the streaming
+ * case, staged here before it goes to the output function) or what will
+ * be the entire buffered result for users of the buffer version.
+ */
+ char *output_buffer;
+ PRUint32 output_buflen; /* the total length of allocated buffer */
+ PRUint32 output_length; /* the length that is currently populated */
+};
+
+PR_END_EXTERN_C
+
+
+/*
+ * Table to convert a binary value to its corresponding ascii "code".
+ */
+static unsigned char base64_valuetocode[64] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+#define B64_PAD '='
+#define B64_CR '\r'
+#define B64_LF '\n'
+
+static PRStatus
+pl_base64_encode_buffer (PLBase64Encoder *data, const unsigned char *in,
+ PRUint32 size)
+{
+ const unsigned char *end = in + size;
+ char *out = data->output_buffer + data->output_length;
+ unsigned int i = data->in_buffer_count;
+ PRUint32 n = 0;
+ int off;
+ PRUint32 output_threshold;
+
+ /* If this input buffer is too small, wait until next time. */
+ if (size < (3 - i)) {
+ data->in_buffer[i++] = in[0];
+ if (size > 1)
+ data->in_buffer[i++] = in[1];
+ PR_ASSERT(i < 3);
+ data->in_buffer_count = i;
+ return PR_SUCCESS;
+ }
+
+ /* If there are bytes that were put back last time, take them now. */
+ if (i > 0) {
+ n = data->in_buffer[0];
+ if (i > 1)
+ n = (n << 8) | data->in_buffer[1];
+ data->in_buffer_count = 0;
+ }
+
+ /* If our total is not a multiple of three, put one or two bytes back. */
+ off = (size + i) % 3;
+ if (off > 0) {
+ size -= off;
+ data->in_buffer[0] = in[size];
+ if (off > 1)
+ data->in_buffer[1] = in[size + 1];
+ data->in_buffer_count = off;
+ end -= off;
+ }
+
+ output_threshold = data->output_buflen - 3;
+
+ /*
+ * Populate the output buffer with base64 data, one line (or buffer)
+ * at a time.
+ */
+ while (in < end) {
+ int j, k;
+
+ while (i < 3) {
+ n = (n << 8) | *in++;
+ i++;
+ }
+ i = 0;
+
+ if (data->line_length > 0) {
+ if (data->current_column >= data->line_length) {
+ data->current_column = 0;
+ *out++ = B64_CR;
+ *out++ = B64_LF;
+ data->output_length += 2;
+ }
+ data->current_column += 4; /* the bytes we are about to add */
+ }
+
+ for (j = 18; j >= 0; j -= 6) {
+ k = (n >> j) & 0x3F;
+ *out++ = base64_valuetocode[k];
+ }
+ n = 0;
+ data->output_length += 4;
+
+ if (data->output_length >= output_threshold) {
+ PR_ASSERT(data->output_length <= data->output_buflen);
+ if (data->output_fn != NULL) {
+ PRInt32 output_result;
+
+ output_result = data->output_fn (data->output_arg,
+ data->output_buffer,
+ (PRInt32) data->output_length);
+ if (output_result < 0)
+ return PR_FAILURE;
+
+ out = data->output_buffer;
+ data->output_length = 0;
+ } else {
+ /*
+ * Check that we are about to exit the loop. (Since we
+ * are over the threshold, there isn't enough room in the
+ * output buffer for another trip around.)
+ */
+ PR_ASSERT(in == end);
+ if (in < end) {
+ PR_SetError (PR_BUFFER_OVERFLOW_ERROR, 0);
+ return PR_FAILURE;
+ }
+ }
+ }
+ }
+
+ return PR_SUCCESS;
+}
+
+static PRStatus
+pl_base64_encode_flush (PLBase64Encoder *data)
+{
+ int i = data->in_buffer_count;
+
+ if (i == 0 && data->output_length == 0)
+ return PR_SUCCESS;
+
+ if (i > 0) {
+ char *out = data->output_buffer + data->output_length;
+ PRUint32 n;
+ int j, k;
+
+ n = ((PRUint32) data->in_buffer[0]) << 16;
+ if (i > 1)
+ n |= ((PRUint32) data->in_buffer[1] << 8);
+
+ data->in_buffer_count = 0;
+
+ if (data->line_length > 0) {
+ if (data->current_column >= data->line_length) {
+ data->current_column = 0;
+ *out++ = B64_CR;
+ *out++ = B64_LF;
+ data->output_length += 2;
+ }
+ }
+
+ /*
+ * This will fill in more than we really have data for, but the
+ * valid parts will end up in the correct position and the extras
+ * will be over-written with pad characters below.
+ */
+ for (j = 18; j >= 0; j -= 6) {
+ k = (n >> j) & 0x3F;
+ *out++ = base64_valuetocode[k];
+ }
+
+ /* Pad with equal-signs. */
+ if (i == 1)
+ out[-2] = B64_PAD;
+ out[-1] = B64_PAD;
+
+ data->output_length += 4;
+ }
+
+ if (data->output_fn != NULL) {
+ PRInt32 output_result;
+
+ output_result = data->output_fn (data->output_arg, data->output_buffer,
+ (PRInt32) data->output_length);
+ data->output_length = 0;
+
+ if (output_result < 0)
+ return PR_FAILURE;
+ }
+
+ return PR_SUCCESS;
+}
+
+
+/*
+ * The maximum space needed to hold the output of the encoder given input
+ * data of length "size", and allowing for CRLF added at least every
+ * line_length bytes (we will add it at nearest lower multiple of 4).
+ * There is no trailing CRLF.
+ */
+static PRUint32
+PL_Base64MaxEncodedLength (PRUint32 size, PRUint32 line_length)
+{
+ PRUint32 tokens, tokens_per_line, full_lines, line_break_chars, remainder;
+
+ tokens = (size + 2) / 3;
+
+ if (line_length == 0)
+ return tokens * 4;
+
+ if (line_length < 4) /* too small! */
+ line_length = 4;
+
+ tokens_per_line = line_length / 4;
+ full_lines = tokens / tokens_per_line;
+ remainder = (tokens - (full_lines * tokens_per_line)) * 4;
+ line_break_chars = full_lines * 2;
+ if (remainder == 0)
+ line_break_chars -= 2;
+
+ return (full_lines * tokens_per_line * 4) + line_break_chars + remainder;
+}
+
+
+/*
+ * A distinct internal creation function for the buffer version to use.
+ * (It does not want to specify an output_fn, and we want the normal
+ * Create function to require that.) All common initialization of the
+ * encoding context should be done *here*.
+ *
+ * Save "line_length", rounded down to nearest multiple of 4 (if not
+ * already even multiple). Allocate output_buffer, if not provided --
+ * based on given size if specified, otherwise based on line_length.
+ */
+static PLBase64Encoder *
+pl_base64_create_encoder (PRUint32 line_length, char *output_buffer,
+ PRUint32 output_buflen)
+{
+ PLBase64Encoder *data;
+ PRUint32 line_tokens;
+
+ data = PR_NEWZAP(PLBase64Encoder);
+ if (data == NULL)
+ return NULL;
+
+ if (line_length > 0 && line_length < 4) /* too small! */
+ line_length = 4;
+
+ line_tokens = line_length / 4;
+ data->line_length = line_tokens * 4;
+
+ if (output_buffer == NULL) {
+ if (output_buflen == 0) {
+ if (data->line_length > 0) /* need to include room for CRLF */
+ output_buflen = data->line_length + 2;
+ else
+ output_buflen = 64; /* XXX what is a good size? */
+ }
+
+ output_buffer = (char *) PR_Malloc(output_buflen);
+ if (output_buffer == NULL) {
+ PR_Free(data);
+ return NULL;
+ }
+ }
+
+ data->output_buffer = output_buffer;
+ data->output_buflen = output_buflen;
+ return data;
+}
+
+/*
+ * Function to start a base64 encoding context.
+ * An "output_fn" is required; the "output_arg" parameter to that is optional.
+ * If linebreaks in the encoded output are desired, "line_length" specifies
+ * where to place them -- it will be rounded down to the nearest multiple of 4
+ * (if it is not already an even multiple of 4). If it is zero, no linebreaks
+ * will be added. (FYI, a linebreak is CRLF -- two characters.)
+ */
+static PLBase64Encoder *
+PL_CreateBase64Encoder (PRInt32 (*output_fn) (void *, const char *, PRInt32),
+ void *output_arg, PRUint32 line_length)
+{
+ PLBase64Encoder *data;
+
+ if (output_fn == NULL) {
+ PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+ return NULL;
+ }
+
+ data = pl_base64_create_encoder (line_length, NULL, 0);
+ if (data == NULL)
+ return NULL;
+
+ data->output_fn = output_fn;
+ data->output_arg = output_arg;
+
+ return data;
+}
+
+
+/*
+ * Push data through the encoder, causing the output_fn (provided to Create)
+ * to be called with the encoded data.
+ */
+static PRStatus
+PL_UpdateBase64Encoder (PLBase64Encoder *data, const unsigned char *buffer,
+ PRUint32 size)
+{
+ /* XXX Should we do argument checking only in debug build? */
+ if (data == NULL || buffer == NULL || size == 0) {
+ PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+ return PR_FAILURE;
+ }
+
+ return pl_base64_encode_buffer (data, buffer, size);
+}
+
+
+/*
+ * When you're done encoding, call this to free the data. If "abort_p"
+ * is false, then calling this may cause the output_fn to be called
+ * one last time (as the last buffered data is flushed out).
+ */
+static PRStatus
+PL_DestroyBase64Encoder (PLBase64Encoder *data, PRBool abort_p)
+{
+ PRStatus status = PR_SUCCESS;
+
+ /* XXX Should we do argument checking only in debug build? */
+ if (data == NULL) {
+ PR_SetError (PR_INVALID_ARGUMENT_ERROR, 0);
+ return PR_FAILURE;
+ }
+
+ /* Flush out the last few buffered characters. */
+ if (!abort_p)
+ status = pl_base64_encode_flush (data);
+
+ if (data->output_buffer != NULL)
+ PR_Free(data->output_buffer);
+ PR_Free(data);
+
+ return status;
+}
+
+
+/*
+ * Perform base64 encoding from an input buffer to an output buffer.
+ * The output buffer can be provided (as "dest"); you can also pass in
+ * a NULL and this function will allocate a buffer large enough for you,
+ * and return it. If you do provide the output buffer, you must also
+ * provide the maximum length of that buffer (as "maxdestlen").
+ * The actual encoded length of output will be returned to you in
+ * "output_destlen".
+ *
+ * If linebreaks in the encoded output are desired, "line_length" specifies
+ * where to place them -- it will be rounded down to the nearest multiple of 4
+ * (if it is not already an even multiple of 4). If it is zero, no linebreaks
+ * will be added. (FYI, a linebreak is CRLF -- two characters.)
+ *
+ * Return value is NULL on error, the output buffer (allocated or provided)
+ * otherwise.
+ */
+static char *
+PL_Base64EncodeBuffer (const unsigned char *src, PRUint32 srclen,
+ PRUint32 line_length, char *dest, PRUint32 maxdestlen,
+ PRUint32 *output_destlen)
+{
+ PRUint32 need_length;
+ PLBase64Encoder *data = NULL;
+ PRStatus status;
+
+ PR_ASSERT(srclen > 0);
+ if (srclen == 0)
+ return dest;
+
+ /*
+ * How much space could we possibly need for encoding this input?
+ */
+ need_length = PL_Base64MaxEncodedLength (srclen, line_length);
+
+ /*
+ * Make sure we have at least that much, if output buffer provided.
+ */
+ if (dest != NULL) {
+ PR_ASSERT(maxdestlen >= need_length);
+ if (maxdestlen < need_length) {
+ PR_SetError(PR_BUFFER_OVERFLOW_ERROR, 0);
+ return NULL;
+ }
+ } else {
+ maxdestlen = need_length;
+ }
+
+ data = pl_base64_create_encoder(line_length, dest, maxdestlen);
+ if (data == NULL)
+ return NULL;
+
+ status = pl_base64_encode_buffer (data, src, srclen);
+
+ /*
+ * We do not wait for Destroy to flush, because Destroy will also
+ * get rid of our encoder context, which we need to look at first!
+ */
+ if (status == PR_SUCCESS)
+ status = pl_base64_encode_flush (data);
+
+ if (status != PR_SUCCESS) {
+ (void) PL_DestroyBase64Encoder (data, PR_TRUE);
+ return NULL;
+ }
+
+ dest = data->output_buffer;
+
+ /* Must clear this or Destroy will free it. */
+ data->output_buffer = NULL;
+
+ *output_destlen = data->output_length;
+ status = PL_DestroyBase64Encoder (data, PR_FALSE);
+ if (status == PR_FAILURE) {
+ PR_Free(dest);
+ return NULL;
+ }
+
+ return dest;
+}
+
+/*
+ * XXX End of base64 encoding code to be moved into NSPR.
+ ********************************************************
+ */
+
+/*
+ * This is the beginning of the NSS cover functions. These will
+ * provide the interface we want to expose as NSS-ish. For example,
+ * they will operate on our Items, do any special handling or checking
+ * we want to do, etc.
+ */
+
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * A boring cover structure for now. Perhaps someday it will include
+ * some more interesting fields.
+ */
+struct NSSBase64EncoderStr {
+ PLBase64Encoder *pl_data;
+};
+
+PR_END_EXTERN_C
+
+
+/*
+ * Function to start a base64 encoding context.
+ */
+NSSBase64Encoder *
+NSSBase64Encoder_Create (PRInt32 (*output_fn) (void *, const char *, PRInt32),
+ void *output_arg)
+{
+ PLBase64Encoder *pl_data;
+ NSSBase64Encoder *nss_data;
+
+ nss_data = PORT_ZNew(NSSBase64Encoder);
+ if (nss_data == NULL)
+ return NULL;
+
+ pl_data = PL_CreateBase64Encoder (output_fn, output_arg, 64);
+ if (pl_data == NULL) {
+ PORT_Free(nss_data);
+ return NULL;
+ }
+
+ nss_data->pl_data = pl_data;
+ return nss_data;
+}
+
+
+/*
+ * Push data through the encoder, causing the output_fn (provided to Create)
+ * to be called with the encoded data.
+ */
+SECStatus
+NSSBase64Encoder_Update (NSSBase64Encoder *data, const unsigned char *buffer,
+ PRUint32 size)
+{
+ PRStatus pr_status;
+
+ /* XXX Should we do argument checking only in debug build? */
+ if (data == NULL) {
+ PORT_SetError (SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ pr_status = PL_UpdateBase64Encoder (data->pl_data, buffer, size);
+ if (pr_status == PR_FAILURE)
+ return SECFailure;
+
+ return SECSuccess;
+}
+
+
+/*
+ * When you're done encoding, call this to free the data. If "abort_p"
+ * is false, then calling this may cause the output_fn to be called
+ * one last time (as the last buffered data is flushed out).
+ */
+SECStatus
+NSSBase64Encoder_Destroy (NSSBase64Encoder *data, PRBool abort_p)
+{
+ PRStatus pr_status;
+
+ /* XXX Should we do argument checking only in debug build? */
+ if (data == NULL) {
+ PORT_SetError (SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ pr_status = PL_DestroyBase64Encoder (data->pl_data, abort_p);
+
+ PORT_Free(data);
+
+ if (pr_status == PR_FAILURE)
+ return SECFailure;
+
+ return SECSuccess;
+}
+
+
+/*
+ * Perform base64 encoding of binary data "inItem" to an ascii string.
+ * The output buffer may be provided (as "outStrOpt"); you can also pass
+ * in a NULL and the buffer will be allocated for you. The result will
+ * be null-terminated, and if the buffer is provided, "maxOutLen" must
+ * specify the maximum length of the buffer and will be checked to
+ * supply sufficient space space for the encoded result. (If "outStrOpt"
+ * is NULL, "maxOutLen" is ignored.)
+ *
+ * If "outStrOpt" is NULL, allocation will happen out of the passed-in
+ * "arenaOpt", if *it* is non-NULL, otherwise standard allocation (heap)
+ * will be used.
+ *
+ * Return value is NULL on error, the output buffer (allocated or provided)
+ * otherwise.
+ */
+char *
+NSSBase64_EncodeItem (PRArenaPool *arenaOpt, char *outStrOpt,
+ unsigned int maxOutLen, SECItem *inItem)
+{
+ char *out_string = outStrOpt;
+ PRUint32 max_out_len;
+ PRUint32 out_len;
+ void *mark = NULL;
+ char *dummy;
+
+ PORT_Assert(inItem != NULL && inItem->data != NULL && inItem->len != 0);
+ if (inItem == NULL || inItem->data == NULL || inItem->len == 0) {
+ PORT_SetError (SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+
+ max_out_len = PL_Base64MaxEncodedLength (inItem->len, 64);
+
+ if (arenaOpt != NULL)
+ mark = PORT_ArenaMark (arenaOpt);
+
+ if (out_string == NULL) {
+ if (arenaOpt != NULL)
+ out_string = PORT_ArenaAlloc (arenaOpt, max_out_len + 1);
+ else
+ out_string = PORT_Alloc (max_out_len + 1);
+
+ if (out_string == NULL) {
+ if (arenaOpt != NULL)
+ PORT_ArenaRelease (arenaOpt, mark);
+ return NULL;
+ }
+ } else {
+ if ((max_out_len + 1) > maxOutLen) {
+ PORT_SetError (SEC_ERROR_OUTPUT_LEN);
+ return NULL;
+ }
+ max_out_len = maxOutLen;
+ }
+
+
+ dummy = PL_Base64EncodeBuffer (inItem->data, inItem->len, 64,
+ out_string, max_out_len, &out_len);
+ if (dummy == NULL) {
+ if (arenaOpt != NULL) {
+ PORT_ArenaRelease (arenaOpt, mark);
+ } else {
+ PORT_Free (out_string);
+ }
+ return NULL;
+ }
+
+ if (arenaOpt != NULL)
+ PORT_ArenaUnmark (arenaOpt, mark);
+
+ out_string[out_len] = '\0';
+ return out_string;
+}
+
+
+/*
+ * XXX Everything below is deprecated. If you add new stuff, put it
+ * *above*, not below.
+ */
+
+/*
+ * XXX The following "BTOA" functions are provided for backward compatibility
+ * with current code. They should be considered strongly deprecated.
+ * When we can convert all our code over to using the new NSSBase64Encoder_
+ * functions defined above, we should get rid of these altogether. (Remove
+ * protoypes from base64.h as well -- actually, remove that file completely).
+ * If someone thinks either of these functions provides such a very useful
+ * interface (though, as shown, the same functionality can already be
+ * obtained by calling NSSBase64_EncodeItem directly), fine -- but then
+ * that API should be provided with a nice new NSSFoo name and using
+ * appropriate types, etc.
+ */
+
+#include "base64.h"
+
+/*
+** Return an PORT_Alloc'd ascii string which is the base64 encoded
+** version of the input string.
+*/
+char *
+BTOA_DataToAscii(const unsigned char *data, unsigned int len)
+{
+ SECItem binary_item;
+
+ binary_item.data = (unsigned char *)data;
+ binary_item.len = len;
+
+ return NSSBase64_EncodeItem (NULL, NULL, 0, &binary_item);
+}
+
+/*
+** Convert from binary encoding of an item to ascii.
+*/
+char *
+BTOA_ConvertItemToAscii (SECItem *binary_item)
+{
+ return NSSBase64_EncodeItem (NULL, NULL, 0, binary_item);
+}
diff --git a/security/nss/lib/util/nssb64t.h b/security/nss/lib/util/nssb64t.h
new file mode 100644
index 000000000..3ca930c7c
--- /dev/null
+++ b/security/nss/lib/util/nssb64t.h
@@ -0,0 +1,49 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Public data structures for base64 encoding/decoding.
+ *
+ * $Id$
+ */
+#ifndef _NSSB64T_H_
+#define _NSSB64T_H_
+
+#include "utilrename.h"
+typedef struct NSSBase64DecoderStr NSSBase64Decoder;
+typedef struct NSSBase64EncoderStr NSSBase64Encoder;
+
+#endif /* _NSSB64T_H_ */
diff --git a/security/nss/lib/util/nssilckt.h b/security/nss/lib/util/nssilckt.h
new file mode 100644
index 000000000..797b4e123
--- /dev/null
+++ b/security/nss/lib/util/nssilckt.h
@@ -0,0 +1,223 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+** nssilock.h - Instrumented locking functions for NSS
+**
+** Description:
+** nssilock provides instrumentation for locks and monitors in
+** the NSS libraries. The instrumentation, when enabled, causes
+** each call to the instrumented function to record data about
+** the call to an external file. The external file
+** subsequently used to extract performance data and other
+** statistical information about the operation of locks used in
+** the nss library.
+**
+** To enable compilation with instrumentation, build NSS with
+** the compile time switch NEED_NSS_ILOCK defined.
+**
+** say: "gmake OS_CFLAGS+=-DNEED_NSS_ILOCK" at make time.
+**
+** At runtime, to enable recording from nssilock, one or more
+** environment variables must be set. For each nssILockType to
+** be recorded, an environment variable of the form NSS_ILOCK_x
+** must be set to 1. For example:
+**
+** set NSS_ILOCK_Cert=1
+**
+** nssilock uses PRLOG is used to record to trace data. The
+** PRLogModule name associated with nssilock data is: "nssilock".
+** To enable recording of nssilock data you will need to set the
+** environment variable NSPR_LOG_MODULES to enable
+** recording for the nssilock log module. Similarly, you will
+** need to set the environment variable NSPR_LOG_FILE to specify
+** the filename to receive the recorded data. See prlog.h for usage.
+** Example:
+**
+** export NSPR_LOG_MODULES=nssilock:6
+** export NSPR_LOG_FILE=xxxLogfile
+**
+** Operation:
+** nssilock wraps calls to NSPR's PZLock and PZMonitor functions
+** with similarly named functions: PZ_NewLock(), etc. When NSS is
+** built with lock instrumentation enabled, the PZ* functions are
+** compiled into NSS; when lock instrumentation is disabled,
+** calls to PZ* functions are directly mapped to PR* functions
+** and the instrumentation arguments to the PZ* functions are
+** compiled away.
+**
+**
+** File Format:
+** The format of the external file is implementation
+** dependent. Where NSPR's PR_LOG() function is used, the file
+** contains data defined for PR_LOG() plus the data written by
+** the wrapped function. On some platforms and under some
+** circumstances, platform dependent logging or
+** instrumentation probes may be used. In any case, the
+** relevant data provided by the lock instrumentation is:
+**
+** lockType, func, address, duration, line, file [heldTime]
+**
+** where:
+**
+** lockType: a character representation of nssILockType for the
+** call. e.g. ... "cert"
+**
+** func: the function doing the tracing. e.g. "NewLock"
+**
+** address: address of the instrumented lock or monitor
+**
+** duration: is how long was spent in the instrumented function,
+** in PRIntervalTime "ticks".
+**
+** line: the line number within the calling function
+**
+** file: the file from which the call was made
+**
+** heldTime: how long the lock/monitor was held. field
+** present only for PZ_Unlock() and PZ_ExitMonitor().
+**
+** Design Notes:
+** The design for lock instrumentation was influenced by the
+** need to gather performance data on NSS 3.x. It is intended
+** that the effort to modify NSS to use lock instrumentation
+** be minimized. Existing calls to locking functions need only
+** have their names changed to the instrumentation function
+** names.
+**
+** Private NSS Interface:
+** nssilock.h defines a private interface for use by NSS.
+** nssilock.h is experimental in nature and is subject to
+** change or revocation without notice. ... Don't mess with
+** it.
+**
+*/
+
+/*
+ * $Id:
+ */
+
+#ifndef _NSSILCKT_H_
+#define _NSSILCKT_H_
+
+#include "utilrename.h"
+#include "prtypes.h"
+#include "prmon.h"
+#include "prlock.h"
+#include "prcvar.h"
+
+typedef enum {
+ nssILockArena = 0,
+ nssILockSession = 1,
+ nssILockObject = 2,
+ nssILockRefLock = 3,
+ nssILockCert = 4,
+ nssILockCertDB = 5,
+ nssILockDBM = 6,
+ nssILockCache = 7,
+ nssILockSSL = 8,
+ nssILockList = 9,
+ nssILockSlot = 10,
+ nssILockFreelist = 11,
+ nssILockOID = 12,
+ nssILockAttribute = 13,
+ nssILockPK11cxt = 14, /* pk11context */
+ nssILockRWLock = 15,
+ nssILockOther = 16,
+ nssILockSelfServ = 17,
+ nssILockKeyDB = 18,
+ nssILockLast /* don't use this one! */
+} nssILockType;
+
+/*
+** conditionally compile in nssilock features
+*/
+#if defined(NEED_NSS_ILOCK)
+
+/*
+** Declare operation type enumerator
+** enumerations identify the function being performed
+*/
+typedef enum {
+ FlushTT = 0,
+ NewLock = 1,
+ Lock = 2,
+ Unlock = 3,
+ DestroyLock = 4,
+ NewCondVar = 5,
+ WaitCondVar = 6,
+ NotifyCondVar = 7,
+ NotifyAllCondVar = 8,
+ DestroyCondVar = 9,
+ NewMonitor = 10,
+ EnterMonitor = 11,
+ ExitMonitor = 12,
+ Notify = 13,
+ NotifyAll = 14,
+ Wait = 15,
+ DestroyMonitor = 16
+} nssILockOp;
+
+/*
+** Declare the trace record
+*/
+struct pzTrace_s {
+ PRUint32 threadID; /* PR_GetThreadID() */
+ nssILockOp op; /* operation being performed */
+ nssILockType ltype; /* lock type identifier */
+ PRIntervalTime callTime; /* time spent in function */
+ PRIntervalTime heldTime; /* lock held time, or -1 */
+ void *lock; /* address of lock structure */
+ PRIntn line; /* line number */
+ char file[24]; /* filename */
+};
+
+/*
+** declare opaque types. See: nssilock.c
+*/
+typedef struct pzlock_s PZLock;
+typedef struct pzcondvar_s PZCondVar;
+typedef struct pzmonitor_s PZMonitor;
+
+#else /* NEED_NSS_ILOCK */
+
+#define PZLock PRLock
+#define PZCondVar PRCondVar
+#define PZMonitor PRMonitor
+
+#endif /* NEED_NSS_ILOCK */
+
+#endif /* _NSSILCKT_H_ */
diff --git a/security/nss/lib/util/nssilock.c b/security/nss/lib/util/nssilock.c
new file mode 100644
index 000000000..afeb8ddb5
--- /dev/null
+++ b/security/nss/lib/util/nssilock.c
@@ -0,0 +1,530 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * nssilock.c - NSS lock instrumentation wrapper functions
+ *
+ * NOTE - These are not public interfaces
+ *
+ * Implementation Notes:
+ * I've tried to make the instrumentation relatively non-intrusive.
+ * To do this, I have used a single PR_LOG() call in each
+ * instrumented function. There's room for improvement.
+ *
+ *
+ */
+
+#include "prinit.h"
+#include "prerror.h"
+#include "prlock.h"
+#include "prmem.h"
+#include "prenv.h"
+#include "prcvar.h"
+#include "prio.h"
+
+#if defined(NEED_NSS_ILOCK)
+#include "prlog.h"
+#include "nssilock.h"
+
+/*
+** Declare the instrumented PZLock
+*/
+struct pzlock_s {
+ PRLock *lock; /* the PZLock to be instrumented */
+ PRIntervalTime time; /* timestamp when the lock was aquired */
+ nssILockType ltype;
+};
+
+/*
+** Declare the instrumented PZMonitor
+*/
+struct pzmonitor_s {
+ PRMonitor *mon; /* the PZMonitor to be instrumented */
+ PRIntervalTime time; /* timestamp when the monitor was aquired */
+ nssILockType ltype;
+};
+
+/*
+** Declare the instrumented PZCondVar
+*/
+struct pzcondvar_s {
+ PRCondVar *cvar; /* the PZCondVar to be instrumented */
+ nssILockType ltype;
+};
+
+
+/*
+** Define a CallOnce type to ensure serialized self-initialization
+*/
+static PRCallOnceType coNssILock; /* CallOnce type */
+static PRIntn nssILockInitialized; /* initialization done when 1 */
+static PRLogModuleInfo *nssILog; /* Log instrumentation to this handle */
+
+
+#define NUM_TT_ENTRIES 6000000
+static PRInt32 traceIndex = -1; /* index into trace table */
+static struct pzTrace_s *tt; /* pointer to trace table */
+static PRInt32 ttBufSize = (NUM_TT_ENTRIES * sizeof(struct pzTrace_s ));
+static PRCondVar *ttCVar;
+static PRLock *ttLock;
+static PRFileDesc *ttfd; /* trace table file */
+
+/*
+** Vtrace() -- Trace events, write events to external media
+**
+** Vtrace() records traced events in an in-memory trace table
+** when the trace table fills, Vtrace writes the entire table
+** to a file.
+**
+** data can be lost!
+**
+*/
+static void Vtrace(
+ nssILockOp op,
+ nssILockType ltype,
+ PRIntervalTime callTime,
+ PRIntervalTime heldTime,
+ void *lock,
+ PRIntn line,
+ char *file
+) {
+ PRInt32 idx;
+ struct pzTrace_s *tp;
+
+RetryTrace:
+ idx = PR_AtomicIncrement( &traceIndex );
+ while( NUM_TT_ENTRIES <= idx || op == FlushTT ) {
+ if( NUM_TT_ENTRIES == idx || op == FlushTT ) {
+ int writeSize = idx * sizeof(struct pzTrace_s);
+ PR_Lock(ttLock);
+ PR_Write( ttfd, tt, writeSize );
+ traceIndex = -1;
+ PR_NotifyAllCondVar( ttCVar );
+ PR_Unlock(ttLock);
+ goto RetryTrace;
+ } else {
+ PR_Lock(ttLock);
+ while( NUM_TT_ENTRIES < idx )
+ PR_WaitCondVar(ttCVar, PR_INTERVAL_NO_WAIT);
+ PR_Unlock(ttLock);
+ goto RetryTrace;
+ }
+ } /* end while() */
+
+ /* create the trace entry */
+ tp = tt + idx;
+ tp->threadID = PR_GetThreadID(PR_GetCurrentThread());
+ tp->op = op;
+ tp->ltype = ltype;
+ tp->callTime = callTime;
+ tp->heldTime = heldTime;
+ tp->lock = lock;
+ tp ->line = line;
+ strcpy(tp->file, file );
+ return;
+} /* --- end Vtrace() --- */
+
+/*
+** pz_TraceFlush() -- Force trace table write to file
+**
+*/
+extern void pz_TraceFlush( void )
+{
+ Vtrace( FlushTT, nssILockSelfServ, 0, 0, NULL, 0, "" );
+ return;
+} /* --- end pz_TraceFlush() --- */
+
+/*
+** nssILockInit() -- Initialization for nssilock
+**
+** This function is called from the CallOnce mechanism.
+*/
+static PRStatus
+ nssILockInit( void )
+{
+ int i;
+ nssILockInitialized = 1;
+
+ /* new log module */
+ nssILog = PR_NewLogModule("nssilock");
+ if ( NULL == nssILog ) {
+ return(PR_FAILURE);
+ }
+
+ tt = PR_Calloc( NUM_TT_ENTRIES, sizeof(struct pzTrace_s));
+ if (NULL == tt ) {
+ fprintf(stderr, "nssilock: can't allocate trace table\n");
+ exit(1);
+ }
+
+ ttfd = PR_Open( "xxxTTLog", PR_CREATE_FILE | PR_WRONLY, 0666 );
+ if ( NULL == ttfd ) {
+ fprintf( stderr, "Oh Drat! Can't open 'xxxTTLog'\n");
+ exit(1);
+ }
+
+ ttLock = PR_NewLock();
+ ttCVar = PR_NewCondVar(ttLock);
+
+ return(PR_SUCCESS);
+} /* --- end nssILockInit() --- */
+
+extern PZLock * pz_NewLock(
+ nssILockType ltype,
+ char *file,
+ PRIntn line )
+{
+ PRStatus rc;
+ PZLock *lock;
+
+ /* Self Initialize the nssILock feature */
+ if (!nssILockInitialized) {
+ rc = PR_CallOnce( &coNssILock, nssILockInit );
+ if ( PR_FAILURE == rc ) {
+ PR_SetError( PR_UNKNOWN_ERROR, 0 );
+ return( NULL );
+ }
+ }
+
+ lock = PR_NEWZAP( PZLock );
+ if ( NULL != lock ) {
+ lock->ltype = ltype;
+ lock->lock = PR_NewLock();
+ if ( NULL == lock->lock ) {
+ PR_DELETE( lock );
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+ } else {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+
+ Vtrace( NewLock, ltype, 0, 0, lock, line, file );
+ return(lock);
+} /* --- end pz_NewLock() --- */
+
+extern void
+ pz_Lock(
+ PZLock *lock,
+ char *file,
+ PRIntn line
+ )
+{
+ PRIntervalTime callTime;
+
+ callTime = PR_IntervalNow();
+ PR_Lock( lock->lock );
+ lock->time = PR_IntervalNow();
+ callTime = lock->time - callTime;
+
+ Vtrace( Lock, lock->ltype, callTime, 0, lock, line, file );
+ return;
+} /* --- end pz_Lock() --- */
+
+extern PRStatus
+ pz_Unlock(
+ PZLock *lock,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+ PRIntervalTime callTime, now, heldTime;
+
+ callTime = PR_IntervalNow();
+ rc = PR_Unlock( lock->lock );
+ now = PR_IntervalNow();
+ callTime = now - callTime;
+ heldTime = now - lock->time;
+ Vtrace( Unlock, lock->ltype, callTime, heldTime, lock, line, file );
+ return( rc );
+} /* --- end pz_Unlock() --- */
+
+extern void
+ pz_DestroyLock(
+ PZLock *lock,
+ char *file,
+ PRIntn line
+ )
+{
+ Vtrace( DestroyLock, lock->ltype, 0, 0, lock, line, file );
+ PR_DestroyLock( lock->lock );
+ PR_DELETE( lock );
+ return;
+} /* --- end pz_DestroyLock() --- */
+
+
+
+extern PZCondVar *
+ pz_NewCondVar(
+ PZLock *lock,
+ char *file,
+ PRIntn line
+ )
+{
+ PZCondVar *cvar;
+
+ cvar = PR_NEWZAP( PZCondVar );
+ if ( NULL == cvar ) {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ } else {
+ cvar->ltype = lock->ltype;
+ cvar->cvar = PR_NewCondVar( lock->lock );
+ if ( NULL == cvar->cvar ) {
+ PR_DELETE( cvar );
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+
+ }
+ Vtrace( NewCondVar, lock->ltype, 0, 0, cvar, line, file );
+ return( cvar );
+} /* --- end pz_NewCondVar() --- */
+
+extern void
+ pz_DestroyCondVar(
+ PZCondVar *cvar,
+ char *file,
+ PRIntn line
+ )
+{
+ Vtrace( DestroyCondVar, cvar->ltype, 0, 0, cvar, line, file );
+ PR_DestroyCondVar( cvar->cvar );
+ PR_DELETE( cvar );
+} /* --- end pz_DestroyCondVar() --- */
+
+extern PRStatus
+ pz_WaitCondVar(
+ PZCondVar *cvar,
+ PRIntervalTime timeout,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+ PRIntervalTime callTime;
+
+ callTime = PR_IntervalNow();
+ rc = PR_WaitCondVar( cvar->cvar, timeout );
+ callTime = PR_IntervalNow() - callTime;
+
+ Vtrace( WaitCondVar, cvar->ltype, callTime, 0, cvar, line, file );
+ return(rc);
+} /* --- end pz_WaitCondVar() --- */
+
+extern PRStatus
+ pz_NotifyCondVar(
+ PZCondVar *cvar,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+
+ rc = PR_NotifyCondVar( cvar->cvar );
+
+ Vtrace( NotifyCondVar, cvar->ltype, 0, 0, cvar, line, file );
+ return(rc);
+} /* --- end pz_NotifyCondVar() --- */
+
+extern PRStatus
+ pz_NotifyAllCondVar(
+ PZCondVar *cvar,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+
+ rc = PR_NotifyAllCondVar( cvar->cvar );
+
+ Vtrace( NotifyAllCondVar, cvar->ltype, 0, 0, cvar, line, file );
+ return(rc);
+} /* --- end pz_NotifyAllCondVar() --- */
+
+extern PZMonitor *
+ pz_NewMonitor(
+ nssILockType ltype,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+ PZMonitor *mon;
+
+ /* Self Initialize the nssILock feature */
+ if (!nssILockInitialized) {
+ rc = PR_CallOnce( &coNssILock, nssILockInit );
+ if ( PR_FAILURE == rc ) {
+ PR_SetError( PR_UNKNOWN_ERROR, 0 );
+ return( NULL );
+ }
+ }
+
+ mon = PR_NEWZAP( PZMonitor );
+ if ( NULL != mon ) {
+ mon->ltype = ltype;
+ mon->mon = PR_NewMonitor();
+ if ( NULL == mon->mon ) {
+ PR_DELETE( mon );
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+ } else {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+
+ Vtrace( NewMonitor, ltype, 0, 0, mon, line, file );
+ return(mon);
+} /* --- end pz_NewMonitor() --- */
+
+extern void
+ pz_DestroyMonitor(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ )
+{
+ Vtrace( DestroyMonitor, mon->ltype, 0, 0, mon, line, file );
+ PR_DestroyMonitor( mon->mon );
+ PR_DELETE( mon );
+ return;
+} /* --- end pz_DestroyMonitor() --- */
+
+extern void
+ pz_EnterMonitor(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ )
+{
+ PRIntervalTime callTime, now;
+
+ callTime = PR_IntervalNow();
+ PR_EnterMonitor( mon->mon );
+ now = PR_IntervalNow();
+ callTime = now - callTime;
+ if ( PR_GetMonitorEntryCount(mon->mon) == 1 ) {
+ mon->time = now;
+ }
+ Vtrace( EnterMonitor, mon->ltype, callTime, 0, mon, line, file );
+ return;
+} /* --- end pz_EnterMonitor() --- */
+
+extern PRStatus
+ pz_ExitMonitor(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+ PRIntervalTime callTime, now, heldTime;
+ PRIntn mec = PR_GetMonitorEntryCount( mon->mon );
+
+ heldTime = (PRIntervalTime)-1;
+ callTime = PR_IntervalNow();
+ rc = PR_ExitMonitor( mon->mon );
+ now = PR_IntervalNow();
+ callTime = now - callTime;
+ if ( mec == 1 )
+ heldTime = now - mon->time;
+ Vtrace( ExitMonitor, mon->ltype, callTime, heldTime, mon, line, file );
+ return( rc );
+} /* --- end pz_ExitMonitor() --- */
+
+extern PRIntn
+ pz_GetMonitorEntryCount(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ )
+{
+ return( PR_GetMonitorEntryCount(mon->mon));
+} /* --- end pz_GetMonitorEntryCount() --- */
+
+
+extern PRStatus
+ pz_Wait(
+ PZMonitor *mon,
+ PRIntervalTime ticks,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+ PRIntervalTime callTime;
+
+ callTime = PR_IntervalNow();
+ rc = PR_Wait( mon->mon, ticks );
+ callTime = PR_IntervalNow() - callTime;
+ Vtrace( Wait, mon->ltype, callTime, 0, mon, line, file );
+ return( rc );
+} /* --- end pz_Wait() --- */
+
+extern PRStatus
+ pz_Notify(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+ PRIntervalTime callTime;
+
+ callTime = PR_IntervalNow();
+ rc = PR_Notify( mon->mon );
+ callTime = PR_IntervalNow() - callTime;
+ Vtrace( Notify, mon->ltype, callTime, 0, mon, line, file );
+ return( rc );
+} /* --- end pz_Notify() --- */
+
+extern PRStatus
+ pz_NotifyAll(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ )
+{
+ PRStatus rc;
+ PRIntervalTime callTime;
+
+ callTime = PR_IntervalNow();
+ rc = PR_NotifyAll( mon->mon );
+ callTime = PR_IntervalNow() - callTime;
+ Vtrace( NotifyAll, mon->ltype, callTime, 0, mon, line, file );
+ return( rc );
+} /* --- end pz_NotifyAll() --- */
+
+#endif /* NEED_NSS_ILOCK */
+/* --- end nssilock.c --------------------------------- */
diff --git a/security/nss/lib/util/nssilock.h b/security/nss/lib/util/nssilock.h
new file mode 100644
index 000000000..c99abf245
--- /dev/null
+++ b/security/nss/lib/util/nssilock.h
@@ -0,0 +1,320 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+** nssilock.h - Instrumented locking functions for NSS
+**
+** Description:
+** nssilock provides instrumentation for locks and monitors in
+** the NSS libraries. The instrumentation, when enabled, causes
+** each call to the instrumented function to record data about
+** the call to an external file. The external file
+** subsequently used to extract performance data and other
+** statistical information about the operation of locks used in
+** the nss library.
+**
+** To enable compilation with instrumentation, build NSS with
+** the compile time switch NEED_NSS_ILOCK defined.
+**
+** say: "gmake OS_CFLAGS+=-DNEED_NSS_ILOCK" at make time.
+**
+** At runtime, to enable recording from nssilock, one or more
+** environment variables must be set. For each nssILockType to
+** be recorded, an environment variable of the form NSS_ILOCK_x
+** must be set to 1. For example:
+**
+** set NSS_ILOCK_Cert=1
+**
+** nssilock uses PRLOG is used to record to trace data. The
+** PRLogModule name associated with nssilock data is: "nssilock".
+** To enable recording of nssilock data you will need to set the
+** environment variable NSPR_LOG_MODULES to enable
+** recording for the nssilock log module. Similarly, you will
+** need to set the environment variable NSPR_LOG_FILE to specify
+** the filename to receive the recorded data. See prlog.h for usage.
+** Example:
+**
+** export NSPR_LOG_MODULES=nssilock:6
+** export NSPR_LOG_FILE=xxxLogfile
+**
+** Operation:
+** nssilock wraps calls to NSPR's PZLock and PZMonitor functions
+** with similarly named functions: PZ_NewLock(), etc. When NSS is
+** built with lock instrumentation enabled, the PZ* functions are
+** compiled into NSS; when lock instrumentation is disabled,
+** calls to PZ* functions are directly mapped to PR* functions
+** and the instrumentation arguments to the PZ* functions are
+** compiled away.
+**
+**
+** File Format:
+** The format of the external file is implementation
+** dependent. Where NSPR's PR_LOG() function is used, the file
+** contains data defined for PR_LOG() plus the data written by
+** the wrapped function. On some platforms and under some
+** circumstances, platform dependent logging or
+** instrumentation probes may be used. In any case, the
+** relevant data provided by the lock instrumentation is:
+**
+** lockType, func, address, duration, line, file [heldTime]
+**
+** where:
+**
+** lockType: a character representation of nssILockType for the
+** call. e.g. ... "cert"
+**
+** func: the function doing the tracing. e.g. "NewLock"
+**
+** address: address of the instrumented lock or monitor
+**
+** duration: is how long was spent in the instrumented function,
+** in PRIntervalTime "ticks".
+**
+** line: the line number within the calling function
+**
+** file: the file from which the call was made
+**
+** heldTime: how long the lock/monitor was held. field
+** present only for PZ_Unlock() and PZ_ExitMonitor().
+**
+** Design Notes:
+** The design for lock instrumentation was influenced by the
+** need to gather performance data on NSS 3.x. It is intended
+** that the effort to modify NSS to use lock instrumentation
+** be minimized. Existing calls to locking functions need only
+** have their names changed to the instrumentation function
+** names.
+**
+** Private NSS Interface:
+** nssilock.h defines a private interface for use by NSS.
+** nssilock.h is experimental in nature and is subject to
+** change or revocation without notice. ... Don't mess with
+** it.
+**
+*/
+
+/*
+ * $Id:
+ */
+
+#ifndef _NSSILOCK_H_
+#define _NSSILOCK_H_
+
+#include "utilrename.h"
+#include "prtypes.h"
+#include "prmon.h"
+#include "prlock.h"
+#include "prcvar.h"
+
+#include "nssilckt.h"
+
+PR_BEGIN_EXTERN_C
+
+#if defined(NEED_NSS_ILOCK)
+
+#define PZ_NewLock(t) pz_NewLock((t),__FILE__,__LINE__)
+extern PZLock *
+ pz_NewLock(
+ nssILockType ltype,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_Lock(k) pz_Lock((k),__FILE__,__LINE__)
+extern void
+ pz_Lock(
+ PZLock *lock,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_Unlock(k) pz_Unlock((k),__FILE__,__LINE__)
+extern PRStatus
+ pz_Unlock(
+ PZLock *lock,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_DestroyLock(k) pz_DestroyLock((k),__FILE__,__LINE__)
+extern void
+ pz_DestroyLock(
+ PZLock *lock,
+ char *file,
+ PRIntn line
+ );
+
+
+#define PZ_NewCondVar(l) pz_NewCondVar((l),__FILE__,__LINE__)
+extern PZCondVar *
+ pz_NewCondVar(
+ PZLock *lock,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_DestroyCondVar(v) pz_DestroyCondVar((v),__FILE__,__LINE__)
+extern void
+ pz_DestroyCondVar(
+ PZCondVar *cvar,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_WaitCondVar(v,t) pz_WaitCondVar((v),(t),__FILE__,__LINE__)
+extern PRStatus
+ pz_WaitCondVar(
+ PZCondVar *cvar,
+ PRIntervalTime timeout,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_NotifyCondVar(v) pz_NotifyCondVar((v),__FILE__,__LINE__)
+extern PRStatus
+ pz_NotifyCondVar(
+ PZCondVar *cvar,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_NotifyAllCondVar(v) pz_NotifyAllCondVar((v),__FILE__,__LINE__)
+extern PRStatus
+ pz_NotifyAllCondVar(
+ PZCondVar *cvar,
+ char *file,
+ PRIntn line
+ );
+
+
+#define PZ_NewMonitor(t) pz_NewMonitor((t),__FILE__,__LINE__)
+extern PZMonitor *
+ pz_NewMonitor(
+ nssILockType ltype,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_DestroyMonitor(m) pz_DestroyMonitor((m),__FILE__,__LINE__)
+extern void
+ pz_DestroyMonitor(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_EnterMonitor(m) pz_EnterMonitor((m),__FILE__,__LINE__)
+extern void
+ pz_EnterMonitor(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ );
+
+
+#define PZ_ExitMonitor(m) pz_ExitMonitor((m),__FILE__,__LINE__)
+extern PRStatus
+ pz_ExitMonitor(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_InMonitor(m) (PZ_GetMonitorEntryCount(m) > 0 )
+#define PZ_GetMonitorEntryCount(m) pz_GetMonitorEntryCount((m),__FILE__,__LINE__)
+extern PRIntn
+ pz_GetMonitorEntryCount(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_Wait(m,i) pz_Wait((m),((i)),__FILE__,__LINE__)
+extern PRStatus
+ pz_Wait(
+ PZMonitor *mon,
+ PRIntervalTime ticks,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_Notify(m) pz_Notify((m),__FILE__,__LINE__)
+extern PRStatus
+ pz_Notify(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_NotifyAll(m) pz_NotifyAll((m),__FILE__,__LINE__)
+extern PRStatus
+ pz_NotifyAll(
+ PZMonitor *mon,
+ char *file,
+ PRIntn line
+ );
+
+#define PZ_TraceFlush() pz_TraceFlush()
+extern void pz_TraceFlush( void );
+
+#else /* NEED_NSS_ILOCK */
+
+#define PZ_NewLock(t) PR_NewLock()
+#define PZ_DestroyLock(k) PR_DestroyLock((k))
+#define PZ_Lock(k) PR_Lock((k))
+#define PZ_Unlock(k) PR_Unlock((k))
+
+#define PZ_NewCondVar(l) PR_NewCondVar((l))
+#define PZ_DestroyCondVar(v) PR_DestroyCondVar((v))
+#define PZ_WaitCondVar(v,t) PR_WaitCondVar((v),(t))
+#define PZ_NotifyCondVar(v) PR_NotifyCondVar((v))
+#define PZ_NotifyAllCondVar(v) PR_NotifyAllCondVar((v))
+
+#define PZ_NewMonitor(t) PR_NewMonitor()
+#define PZ_DestroyMonitor(m) PR_DestroyMonitor((m))
+#define PZ_EnterMonitor(m) PR_EnterMonitor((m))
+#define PZ_ExitMonitor(m) PR_ExitMonitor((m))
+#define PZ_InMonitor(m) PR_InMonitor((m))
+#define PZ_Wait(m,t) PR_Wait(((m)),((t)))
+#define PZ_Notify(m) PR_Notify((m))
+#define PZ_NotifyAll(m) PR_Notify((m))
+#define PZ_TraceFlush() /* nothing */
+
+
+#endif /* NEED_NSS_ILOCK */
+
+PR_END_EXTERN_C
+#endif /* _NSSILOCK_H_ */
diff --git a/security/nss/lib/util/nsslocks.h b/security/nss/lib/util/nsslocks.h
new file mode 100644
index 000000000..c78850ae9
--- /dev/null
+++ b/security/nss/lib/util/nsslocks.h
@@ -0,0 +1,45 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * nsslocks.h - threadsafe functions to initialize lock pointers.
+ *
+ * NOTE - The interfaces formerly in this header were private and are now all
+ * obsolete.
+ *
+ * $Id$
+ */
+
diff --git a/security/nss/lib/util/nssrwlk.c b/security/nss/lib/util/nssrwlk.c
new file mode 100644
index 000000000..c46e36617
--- /dev/null
+++ b/security/nss/lib/util/nssrwlk.c
@@ -0,0 +1,479 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nssrwlk.h"
+#include "nspr.h"
+
+PR_BEGIN_EXTERN_C
+
+/*
+ * Reader-writer lock
+ */
+struct nssRWLockStr {
+ PZLock * rw_lock;
+ char * rw_name; /* lock name */
+ PRUint32 rw_rank; /* rank of the lock */
+ PRInt32 rw_writer_locks; /* == 0, if unlocked */
+ PRInt32 rw_reader_locks; /* == 0, if unlocked */
+ /* > 0 , # of read locks */
+ PRUint32 rw_waiting_readers; /* number of waiting readers */
+ PRUint32 rw_waiting_writers; /* number of waiting writers */
+ PZCondVar * rw_reader_waitq; /* cvar for readers */
+ PZCondVar * rw_writer_waitq; /* cvar for writers */
+ PRThread * rw_owner; /* lock owner for write-lock */
+ /* Non-null if write lock held. */
+};
+
+PR_END_EXTERN_C
+
+#include <string.h>
+
+#ifdef DEBUG_RANK_ORDER
+#define NSS_RWLOCK_RANK_ORDER_DEBUG /* enable deadlock detection using
+ rank-order for locks
+ */
+#endif
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+
+static PRUintn nss_thread_rwlock_initialized;
+static PRUintn nss_thread_rwlock; /* TPD key for lock stack */
+static PRUintn nss_thread_rwlock_alloc_failed;
+
+#define _NSS_RWLOCK_RANK_ORDER_LIMIT 10
+
+typedef struct thread_rwlock_stack {
+ PRInt32 trs_index; /* top of stack */
+ NSSRWLock *trs_stack[_NSS_RWLOCK_RANK_ORDER_LIMIT]; /* stack of lock
+ pointers */
+} thread_rwlock_stack;
+
+/* forward static declarations. */
+static PRUint32 nssRWLock_GetThreadRank(PRThread *me);
+static void nssRWLock_SetThreadRank(PRThread *me, NSSRWLock *rwlock);
+static void nssRWLock_UnsetThreadRank(PRThread *me, NSSRWLock *rwlock);
+static void nssRWLock_ReleaseLockStack(void *lock_stack);
+
+#endif
+
+#define UNTIL(x) while(!(x))
+
+/*
+ * Reader/Writer Locks
+ */
+
+/*
+ * NSSRWLock_New
+ * Create a reader-writer lock, with the given lock rank and lock name
+ *
+ */
+
+NSSRWLock *
+NSSRWLock_New(PRUint32 lock_rank, const char *lock_name)
+{
+ NSSRWLock *rwlock;
+
+ rwlock = PR_NEWZAP(NSSRWLock);
+ if (rwlock == NULL)
+ return NULL;
+
+ rwlock->rw_lock = PZ_NewLock(nssILockRWLock);
+ if (rwlock->rw_lock == NULL) {
+ goto loser;
+ }
+ rwlock->rw_reader_waitq = PZ_NewCondVar(rwlock->rw_lock);
+ if (rwlock->rw_reader_waitq == NULL) {
+ goto loser;
+ }
+ rwlock->rw_writer_waitq = PZ_NewCondVar(rwlock->rw_lock);
+ if (rwlock->rw_writer_waitq == NULL) {
+ goto loser;
+ }
+ if (lock_name != NULL) {
+ rwlock->rw_name = (char*) PR_Malloc(strlen(lock_name) + 1);
+ if (rwlock->rw_name == NULL) {
+ goto loser;
+ }
+ strcpy(rwlock->rw_name, lock_name);
+ } else {
+ rwlock->rw_name = NULL;
+ }
+ rwlock->rw_rank = lock_rank;
+ rwlock->rw_waiting_readers = 0;
+ rwlock->rw_waiting_writers = 0;
+ rwlock->rw_reader_locks = 0;
+ rwlock->rw_writer_locks = 0;
+
+ return rwlock;
+
+loser:
+ NSSRWLock_Destroy(rwlock);
+ return(NULL);
+}
+
+/*
+** Destroy the given RWLock "lock".
+*/
+void
+NSSRWLock_Destroy(NSSRWLock *rwlock)
+{
+ PR_ASSERT(rwlock != NULL);
+ PR_ASSERT(rwlock->rw_waiting_readers == 0);
+
+ /* XXX Shouldn't we lock the PZLock before destroying this?? */
+
+ if (rwlock->rw_name)
+ PR_Free(rwlock->rw_name);
+ if (rwlock->rw_reader_waitq)
+ PZ_DestroyCondVar(rwlock->rw_reader_waitq);
+ if (rwlock->rw_writer_waitq)
+ PZ_DestroyCondVar(rwlock->rw_writer_waitq);
+ if (rwlock->rw_lock)
+ PZ_DestroyLock(rwlock->rw_lock);
+ PR_DELETE(rwlock);
+}
+
+/*
+** Read-lock the RWLock.
+*/
+void
+NSSRWLock_LockRead(NSSRWLock *rwlock)
+{
+ PRThread *me = PR_GetCurrentThread();
+
+ PZ_Lock(rwlock->rw_lock);
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+
+ /*
+ * assert that rank ordering is not violated; the rank of 'rwlock' should
+ * be equal to or greater than the highest rank of all the locks held by
+ * the thread.
+ */
+ PR_ASSERT((rwlock->rw_rank == NSS_RWLOCK_RANK_NONE) ||
+ (rwlock->rw_rank >= nssRWLock_GetThreadRank(me)));
+#endif
+ /*
+ * wait if write-locked or if a writer is waiting; preference for writers
+ */
+ UNTIL ( (rwlock->rw_owner == me) || /* I own it, or */
+ ((rwlock->rw_owner == NULL) && /* no-one owns it, and */
+ (rwlock->rw_waiting_writers == 0))) { /* no-one is waiting to own */
+
+ rwlock->rw_waiting_readers++;
+ PZ_WaitCondVar(rwlock->rw_reader_waitq, PR_INTERVAL_NO_TIMEOUT);
+ rwlock->rw_waiting_readers--;
+ }
+ rwlock->rw_reader_locks++; /* Increment read-lock count */
+
+ PZ_Unlock(rwlock->rw_lock);
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+ nssRWLock_SetThreadRank(me, rwlock);/* update thread's lock rank */
+#endif
+}
+
+/* Unlock a Read lock held on this RW lock.
+*/
+void
+NSSRWLock_UnlockRead(NSSRWLock *rwlock)
+{
+ PZ_Lock(rwlock->rw_lock);
+
+ PR_ASSERT(rwlock->rw_reader_locks > 0); /* lock must be read locked */
+
+ if (( rwlock->rw_reader_locks > 0) && /* caller isn't screwey */
+ (--rwlock->rw_reader_locks == 0) && /* not read locked any more */
+ ( rwlock->rw_owner == NULL) && /* not write locked */
+ ( rwlock->rw_waiting_writers > 0)) { /* someone's waiting. */
+
+ PZ_NotifyCondVar(rwlock->rw_writer_waitq); /* wake him up. */
+ }
+
+ PZ_Unlock(rwlock->rw_lock);
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+ /*
+ * update thread's lock rank
+ */
+ nssRWLock_UnsetThreadRank(me, rwlock);
+#endif
+ return;
+}
+
+/*
+** Write-lock the RWLock.
+*/
+void
+NSSRWLock_LockWrite(NSSRWLock *rwlock)
+{
+ PRThread *me = PR_GetCurrentThread();
+
+ PZ_Lock(rwlock->rw_lock);
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+ /*
+ * assert that rank ordering is not violated; the rank of 'rwlock' should
+ * be equal to or greater than the highest rank of all the locks held by
+ * the thread.
+ */
+ PR_ASSERT((rwlock->rw_rank == NSS_RWLOCK_RANK_NONE) ||
+ (rwlock->rw_rank >= nssRWLock_GetThreadRank(me)));
+#endif
+ /*
+ * wait if read locked or write locked.
+ */
+ PR_ASSERT(rwlock->rw_reader_locks >= 0);
+ PR_ASSERT(me != NULL);
+
+ UNTIL ( (rwlock->rw_owner == me) || /* I own write lock, or */
+ ((rwlock->rw_owner == NULL) && /* no writer and */
+ (rwlock->rw_reader_locks == 0))) { /* no readers, either. */
+
+ rwlock->rw_waiting_writers++;
+ PZ_WaitCondVar(rwlock->rw_writer_waitq, PR_INTERVAL_NO_TIMEOUT);
+ rwlock->rw_waiting_writers--;
+ PR_ASSERT(rwlock->rw_reader_locks >= 0);
+ }
+
+ PR_ASSERT(rwlock->rw_reader_locks == 0);
+ /*
+ * apply write lock
+ */
+ rwlock->rw_owner = me;
+ rwlock->rw_writer_locks++; /* Increment write-lock count */
+
+ PZ_Unlock(rwlock->rw_lock);
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+ /*
+ * update thread's lock rank
+ */
+ nssRWLock_SetThreadRank(me,rwlock);
+#endif
+}
+
+/* Unlock a Read lock held on this RW lock.
+*/
+void
+NSSRWLock_UnlockWrite(NSSRWLock *rwlock)
+{
+ PRThread *me = PR_GetCurrentThread();
+
+ PZ_Lock(rwlock->rw_lock);
+ PR_ASSERT(rwlock->rw_owner == me); /* lock must be write-locked by me. */
+ PR_ASSERT(rwlock->rw_writer_locks > 0); /* lock must be write locked */
+
+ if ( rwlock->rw_owner == me && /* I own it, and */
+ rwlock->rw_writer_locks > 0 && /* I own it, and */
+ --rwlock->rw_writer_locks == 0) { /* I'm all done with it */
+
+ rwlock->rw_owner = NULL; /* I don't own it any more. */
+
+ /* Give preference to waiting writers. */
+ if (rwlock->rw_waiting_writers > 0) {
+ if (rwlock->rw_reader_locks == 0)
+ PZ_NotifyCondVar(rwlock->rw_writer_waitq);
+ } else if (rwlock->rw_waiting_readers > 0) {
+ PZ_NotifyAllCondVar(rwlock->rw_reader_waitq);
+ }
+ }
+ PZ_Unlock(rwlock->rw_lock);
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+ /*
+ * update thread's lock rank
+ */
+ nssRWLock_UnsetThreadRank(me, rwlock);
+#endif
+ return;
+}
+
+/* This is primarily for debugging, i.e. for inclusion in ASSERT calls. */
+PRBool
+NSSRWLock_HaveWriteLock(NSSRWLock *rwlock) {
+ PRBool ownWriteLock;
+ PRThread *me = PR_GetCurrentThread();
+
+ /* This lock call isn't really necessary.
+ ** If this thread is the owner, that fact cannot change during this call,
+ ** because this thread is in this call.
+ ** If this thread is NOT the owner, the owner could change, but it
+ ** could not become this thread.
+ */
+#if UNNECESSARY
+ PZ_Lock(rwlock->rw_lock);
+#endif
+ ownWriteLock = (PRBool)(me == rwlock->rw_owner);
+#if UNNECESSARY
+ PZ_Unlock(rwlock->rw_lock);
+#endif
+ return ownWriteLock;
+}
+
+#ifdef NSS_RWLOCK_RANK_ORDER_DEBUG
+
+/*
+ * nssRWLock_SetThreadRank
+ * Set a thread's lock rank, which is the highest of the ranks of all
+ * the locks held by the thread. Pointers to the locks are added to a
+ * per-thread list, which is anchored off a thread-private data key.
+ */
+
+static void
+nssRWLock_SetThreadRank(PRThread *me, NSSRWLock *rwlock)
+{
+ thread_rwlock_stack *lock_stack;
+ PRStatus rv;
+
+ /*
+ * allocated thread-private-data for rwlock list, if not already allocated
+ */
+ if (!nss_thread_rwlock_initialized) {
+ /*
+ * allocate tpd, only if not failed already
+ */
+ if (!nss_thread_rwlock_alloc_failed) {
+ if (PR_NewThreadPrivateIndex(&nss_thread_rwlock,
+ nssRWLock_ReleaseLockStack)
+ == PR_FAILURE) {
+ nss_thread_rwlock_alloc_failed = 1;
+ return;
+ }
+ } else
+ return;
+ }
+ /*
+ * allocate a lock stack
+ */
+ if ((lock_stack = PR_GetThreadPrivate(nss_thread_rwlock)) == NULL) {
+ lock_stack = (thread_rwlock_stack *)
+ PR_CALLOC(1 * sizeof(thread_rwlock_stack));
+ if (lock_stack) {
+ rv = PR_SetThreadPrivate(nss_thread_rwlock, lock_stack);
+ if (rv == PR_FAILURE) {
+ PR_DELETE(lock_stack);
+ nss_thread_rwlock_alloc_failed = 1;
+ return;
+ }
+ } else {
+ nss_thread_rwlock_alloc_failed = 1;
+ return;
+ }
+ }
+ /*
+ * add rwlock to lock stack, if limit is not exceeded
+ */
+ if (lock_stack) {
+ if (lock_stack->trs_index < _NSS_RWLOCK_RANK_ORDER_LIMIT)
+ lock_stack->trs_stack[lock_stack->trs_index++] = rwlock;
+ }
+ nss_thread_rwlock_initialized = 1;
+}
+
+static void
+nssRWLock_ReleaseLockStack(void *lock_stack)
+{
+ PR_ASSERT(lock_stack);
+ PR_DELETE(lock_stack);
+}
+
+/*
+ * nssRWLock_GetThreadRank
+ *
+ * return thread's lock rank. If thread-private-data for the lock
+ * stack is not allocated, return NSS_RWLOCK_RANK_NONE.
+ */
+
+static PRUint32
+nssRWLock_GetThreadRank(PRThread *me)
+{
+ thread_rwlock_stack *lock_stack;
+
+ if (nss_thread_rwlock_initialized) {
+ if ((lock_stack = PR_GetThreadPrivate(nss_thread_rwlock)) == NULL)
+ return (NSS_RWLOCK_RANK_NONE);
+ else
+ return(lock_stack->trs_stack[lock_stack->trs_index - 1]->rw_rank);
+
+ } else
+ return (NSS_RWLOCK_RANK_NONE);
+}
+
+/*
+ * nssRWLock_UnsetThreadRank
+ *
+ * remove the rwlock from the lock stack. Since locks may not be
+ * unlocked in a FIFO order, the entire lock stack is searched.
+ */
+
+static void
+nssRWLock_UnsetThreadRank(PRThread *me, NSSRWLock *rwlock)
+{
+ thread_rwlock_stack *lock_stack;
+ int new_index = 0, index, done = 0;
+
+ if (!nss_thread_rwlock_initialized)
+ return;
+
+ lock_stack = PR_GetThreadPrivate(nss_thread_rwlock);
+
+ PR_ASSERT(lock_stack != NULL);
+
+ index = lock_stack->trs_index - 1;
+ while (index-- >= 0) {
+ if ((lock_stack->trs_stack[index] == rwlock) && !done) {
+ /*
+ * reset the slot for rwlock
+ */
+ lock_stack->trs_stack[index] = NULL;
+ done = 1;
+ }
+ /*
+ * search for the lowest-numbered empty slot, above which there are
+ * no non-empty slots
+ */
+ if ((lock_stack->trs_stack[index] != NULL) && !new_index)
+ new_index = index + 1;
+ if (done && new_index)
+ break;
+ }
+ /*
+ * set top of stack to highest numbered empty slot
+ */
+ lock_stack->trs_index = new_index;
+
+}
+
+#endif /* NSS_RWLOCK_RANK_ORDER_DEBUG */
diff --git a/security/nss/lib/util/nssrwlk.h b/security/nss/lib/util/nssrwlk.h
new file mode 100644
index 000000000..914bf3a8a
--- /dev/null
+++ b/security/nss/lib/util/nssrwlk.h
@@ -0,0 +1,164 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+** File: nsrwlock.h
+** Description: API to basic reader-writer lock functions of NSS.
+** These are re-entrant reader writer locks; that is,
+** If I hold the write lock, I can ask for it and get it again.
+** If I hold the write lock, I can also ask for and get a read lock.
+** I can then release the locks in any order (read or write).
+** I must release each lock type as many times as I acquired it.
+** Otherwise, these are normal reader/writer locks.
+**
+** For deadlock detection, locks should be ranked, and no lock may be aquired
+** while I hold a lock of higher rank number.
+** If you don't want that feature, always use NSS_RWLOCK_RANK_NONE.
+** Lock name is for debugging, and is optional (may be NULL)
+**/
+
+#ifndef nssrwlk_h___
+#define nssrwlk_h___
+
+#include "utilrename.h"
+#include "prtypes.h"
+#include "nssrwlkt.h"
+
+#define NSS_RWLOCK_RANK_NONE 0
+
+/* SEC_BEGIN_PROTOS */
+PR_BEGIN_EXTERN_C
+
+/***********************************************************************
+** FUNCTION: NSSRWLock_New
+** DESCRIPTION:
+** Returns a pointer to a newly created reader-writer lock object.
+** INPUTS: Lock rank
+** Lock name
+** OUTPUTS: void
+** RETURN: NSSRWLock*
+** If the lock cannot be created because of resource constraints, NULL
+** is returned.
+**
+***********************************************************************/
+extern NSSRWLock* NSSRWLock_New(PRUint32 lock_rank, const char *lock_name);
+
+/***********************************************************************
+** FUNCTION: NSSRWLock_AtomicCreate
+** DESCRIPTION:
+** Given the address of a NULL pointer to a NSSRWLock,
+** atomically initializes that pointer to a newly created NSSRWLock.
+** Returns the value placed into that pointer, or NULL.
+**
+** INPUTS: address of NSRWLock pointer
+** Lock rank
+** Lock name
+** OUTPUTS: NSSRWLock*
+** RETURN: NSSRWLock*
+** If the lock cannot be created because of resource constraints,
+** the pointer will be left NULL.
+**
+***********************************************************************/
+extern NSSRWLock *
+nssRWLock_AtomicCreate( NSSRWLock ** prwlock,
+ PRUint32 lock_rank,
+ const char * lock_name);
+
+/***********************************************************************
+** FUNCTION: NSSRWLock_Destroy
+** DESCRIPTION:
+** Destroys a given RW lock object.
+** INPUTS: NSSRWLock *lock - Lock to be freed.
+** OUTPUTS: void
+** RETURN: None
+***********************************************************************/
+extern void NSSRWLock_Destroy(NSSRWLock *lock);
+
+/***********************************************************************
+** FUNCTION: NSSRWLock_LockRead
+** DESCRIPTION:
+** Apply a read lock (non-exclusive) on a RWLock
+** INPUTS: NSSRWLock *lock - Lock to be read-locked.
+** OUTPUTS: void
+** RETURN: None
+***********************************************************************/
+extern void NSSRWLock_LockRead(NSSRWLock *lock);
+
+/***********************************************************************
+** FUNCTION: NSSRWLock_LockWrite
+** DESCRIPTION:
+** Apply a write lock (exclusive) on a RWLock
+** INPUTS: NSSRWLock *lock - Lock to write-locked.
+** OUTPUTS: void
+** RETURN: None
+***********************************************************************/
+extern void NSSRWLock_LockWrite(NSSRWLock *lock);
+
+/***********************************************************************
+** FUNCTION: NSSRWLock_UnlockRead
+** DESCRIPTION:
+** Release a Read lock. Unlocking an unlocked lock has undefined results.
+** INPUTS: NSSRWLock *lock - Lock to unlocked.
+** OUTPUTS: void
+** RETURN: void
+***********************************************************************/
+extern void NSSRWLock_UnlockRead(NSSRWLock *lock);
+
+/***********************************************************************
+** FUNCTION: NSSRWLock_UnlockWrite
+** DESCRIPTION:
+** Release a Write lock. Unlocking an unlocked lock has undefined results.
+** INPUTS: NSSRWLock *lock - Lock to unlocked.
+** OUTPUTS: void
+** RETURN: void
+***********************************************************************/
+extern void NSSRWLock_UnlockWrite(NSSRWLock *lock);
+
+/***********************************************************************
+** FUNCTION: NSSRWLock_HaveWriteLock
+** DESCRIPTION:
+** Tells caller whether the current thread holds the write lock, or not.
+** INPUTS: NSSRWLock *lock - Lock to test.
+** OUTPUTS: void
+** RETURN: PRBool PR_TRUE IFF the current thread holds the write lock.
+***********************************************************************/
+
+extern PRBool NSSRWLock_HaveWriteLock(NSSRWLock *rwlock);
+
+/* SEC_END_PROTOS */
+PR_END_EXTERN_C
+
+#endif /* nsrwlock_h___ */
diff --git a/security/nss/lib/util/nssrwlkt.h b/security/nss/lib/util/nssrwlkt.h
new file mode 100644
index 000000000..bb98c0e3c
--- /dev/null
+++ b/security/nss/lib/util/nssrwlkt.h
@@ -0,0 +1,52 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef nssrwlkt_h___
+#define nssrwlkt_h___
+
+#include "utilrename.h"
+#include "nssilock.h"
+/*
+ * NSSRWLock --
+ *
+ * The reader writer lock, NSSRWLock, is an opaque object to the clients
+ * of NSS. All routines operate on a pointer to this opaque entity.
+ */
+
+typedef struct nssRWLockStr NSSRWLock;
+
+
+#endif /* nsrwlock_h___ */
diff --git a/security/nss/lib/util/nssutil.def b/security/nss/lib/util/nssutil.def
new file mode 100644
index 000000000..e3b568915
--- /dev/null
+++ b/security/nss/lib/util/nssutil.def
@@ -0,0 +1,234 @@
+;+#
+;+# ***** BEGIN LICENSE BLOCK *****
+;+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+;+#
+;+# The contents of this file are subject to the Mozilla Public License Version
+;+# 1.1 (the "License"); you may not use this file except in compliance with
+;+# the License. You may obtain a copy of the License at
+;+# http://www.mozilla.org/MPL/
+;+#
+;+# Software distributed under the License is distributed on an "AS IS" basis,
+;+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+;+# for the specific language governing rights and limitations under the
+;+# License.
+;+#
+;+# The Original Code is the Network Security Services libraries.
+;+#
+;+# The Initial Developer of the Original Code is
+;+# Sun Microsystems, Inc.
+;+# Portions created by the Initial Developer are Copyright (C) 2007
+;+# the Initial Developer. All Rights Reserved.
+;+#
+;+# Contributor(s):
+;+#
+;+# Alternatively, the contents of this file may be used under the terms of
+;+# either the GNU General Public License Version 2 or later (the "GPL"), or
+;+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+;+# in which case the provisions of the GPL or the LGPL are applicable instead
+;+# of those above. If you wish to allow use of your version of this file only
+;+# under the terms of either the GPL or the LGPL, and not to allow others to
+;+# use your version of this file under the terms of the MPL, indicate your
+;+# decision by deleting the provisions above and replace them with the notice
+;+# and other provisions required by the GPL or the LGPL. If you do not delete
+;+# the provisions above, a recipient may use your version of this file under
+;+# the terms of any one of the MPL, the GPL or the LGPL.
+;+#
+;+# ***** END LICENSE BLOCK *****
+;+#
+;+# OK, this file is meant to support SUN, LINUX, AIX and WINDOWS
+;+# 1. For all unix platforms, the string ";-" means "remove this line"
+;+# 2. For all unix platforms, the string " DATA " will be removed from any
+;+# line on which it occurs.
+;+# 3. Lines containing ";+" will have ";+" removed on SUN and LINUX.
+;+# On AIX, lines containing ";+" will be removed.
+;+# 4. For all unix platforms, the string ";;" will thave the ";;" removed.
+;+# 5. For all unix platforms, after the above processing has taken place,
+;+# all characters after the first ";" on the line will be removed.
+;+# And for AIX, the first ";" will also be removed.
+;+# This file is passed directly to windows. Since ';' is a comment, all UNIX
+;+# directives are hidden behind ";", ";+", and ";-"
+;+NSSUTIL_3.12 { # NSS Utilities 3.12 release
+;+ global:
+LIBRARY nssutil3 ;-
+EXPORTS ;-
+ATOB_AsciiToData_Util;
+ATOB_ConvertAsciiToItem_Util;
+BTOA_ConvertItemToAscii_Util;
+BTOA_DataToAscii_Util;
+CERT_GenTime2FormattedAscii_Util;
+DER_AsciiToTime_Util;
+DER_DecodeTimeChoice_Util;
+DER_Encode_Util;
+DER_EncodeTimeChoice_Util;
+DER_GeneralizedDayToAscii_Util;
+DER_GeneralizedTimeToTime_Util;
+DER_GetInteger_Util;
+DER_GetUInteger;
+DER_LengthLength;
+DER_Lengths_Util;
+DER_SetUInteger;
+DER_StoreHeader;
+DER_TimeChoiceDayToAscii_Util;
+DER_TimeToGeneralizedTime_Util;
+DER_TimeToGeneralizedTimeArena_Util;
+DER_TimeToUTCTime_Util;
+DER_UTCDayToAscii_Util;
+DER_UTCTimeToAscii_Util;
+DER_UTCTimeToTime_Util;
+NSS_PutEnv_Util;
+NSSBase64_DecodeBuffer_Util;
+NSSBase64_EncodeItem_Util;
+NSSBase64Decoder_Create_Util;
+NSSBase64Decoder_Destroy_Util;
+NSSBase64Decoder_Update_Util;
+NSSBase64Encoder_Create_Util;
+NSSBase64Encoder_Destroy_Util;
+NSSBase64Encoder_Update_Util;
+NSSRWLock_Destroy_Util;
+NSSRWLock_HaveWriteLock_Util;
+NSSRWLock_LockRead_Util;
+NSSRWLock_LockWrite_Util;
+NSSRWLock_New_Util;
+NSSRWLock_UnlockRead_Util;
+NSSRWLock_UnlockWrite_Util;
+PORT_Alloc_Util;
+PORT_ArenaAlloc_Util;
+PORT_ArenaGrow_Util;
+PORT_ArenaMark_Util;
+PORT_ArenaRelease_Util;
+PORT_ArenaStrdup_Util;
+PORT_ArenaUnmark_Util;
+PORT_ArenaZAlloc_Util;
+PORT_Free_Util;
+PORT_FreeArena_Util;
+PORT_GetError_Util;
+PORT_ISO88591_UTF8Conversion;
+PORT_NewArena_Util;
+PORT_Realloc_Util;
+PORT_RegExpCaseSearch;
+PORT_RegExpValid;
+PORT_SetError_Util;
+PORT_SetUCS2_ASCIIConversionFunction_Util;
+PORT_SetUCS2_UTF8ConversionFunction_Util;
+PORT_SetUCS4_UTF8ConversionFunction_Util;
+PORT_Strdup_Util;
+PORT_UCS2_ASCIIConversion_Util;
+PORT_UCS2_UTF8Conversion_Util;
+PORT_UCS4_UTF8Conversion;
+PORT_ZAlloc_Util;
+PORT_ZFree_Util;
+SEC_ASN1Decode_Util;
+SEC_ASN1DecodeInteger_Util;
+SEC_ASN1DecodeItem_Util;
+SEC_ASN1DecoderAbort_Util;
+SEC_ASN1DecoderClearFilterProc_Util;
+SEC_ASN1DecoderClearNotifyProc_Util;
+SEC_ASN1DecoderFinish_Util;
+SEC_ASN1DecoderSetFilterProc_Util;
+SEC_ASN1DecoderSetNotifyProc_Util;
+SEC_ASN1DecoderStart_Util;
+SEC_ASN1DecoderUpdate_Util;
+SEC_ASN1Encode_Util;
+SEC_ASN1EncodeInteger_Util;
+SEC_ASN1EncodeItem_Util;
+SEC_ASN1EncoderAbort_Util;
+SEC_ASN1EncoderClearNotifyProc_Util;
+SEC_ASN1EncoderClearStreaming_Util;
+SEC_ASN1EncoderClearTakeFromBuf_Util;
+SEC_ASN1EncoderFinish_Util;
+SEC_ASN1EncoderSetNotifyProc_Util;
+SEC_ASN1EncoderSetStreaming_Util;
+SEC_ASN1EncoderSetTakeFromBuf_Util;
+SEC_ASN1EncoderStart_Util;
+SEC_ASN1EncoderUpdate_Util;
+SEC_ASN1EncodeUnsignedInteger_Util;
+SEC_ASN1LengthLength_Util;
+SEC_QuickDERDecodeItem_Util;
+SEC_StringToOID;
+SECITEM_AllocItem_Util;
+SECITEM_ArenaDupItem_Util;
+SECITEM_CompareItem_Util;
+SECITEM_CopyItem_Util;
+SECITEM_DupItem_Util;
+SECITEM_FreeItem_Util;
+SECITEM_Hash;
+SECITEM_HashCompare;
+SECITEM_ItemsAreEqual_Util;
+SECITEM_ZfreeItem_Util;
+SECOID_AddEntry_Util;
+SECOID_CompareAlgorithmID_Util;
+SECOID_CopyAlgorithmID_Util;
+SECOID_DestroyAlgorithmID_Util;
+SECOID_FindOID_Util;
+SECOID_FindOIDByMechanism;
+SECOID_FindOIDByTag_Util;
+SECOID_FindOIDTag_Util;
+SECOID_FindOIDTagDescription_Util;
+SECOID_GetAlgorithmTag_Util;
+SECOID_Init;
+SECOID_KnownCertExtenOID;
+SECOID_SetAlgorithmID_Util;
+SECOID_Shutdown;
+SGN_CompareDigestInfo_Util;
+SGN_CopyDigestInfo_Util;
+SGN_CreateDigestInfo_Util;
+SGN_DecodeDigestInfo;
+SGN_DestroyDigestInfo_Util;
+;+#
+;+# Data objects
+;+#
+;+# Don't export these DATA symbols on Windows because they don't work right.
+;+# Use the SEC_ASN1_GET / SEC_ASN1_SUB / SEC_ASN1_XTRN macros to access them.
+;;SEC_AnyTemplate_Util DATA ;
+;;SEC_BitStringTemplate_Util DATA ;
+;;SEC_BMPStringTemplate_Util DATA ;
+;;SEC_BooleanTemplate_Util DATA ;
+;;SEC_EnumeratedTemplate DATA ;
+;;SEC_GeneralizedTimeTemplate_Util DATA ;
+;;SEC_IA5StringTemplate_Util DATA ;
+;;SEC_IntegerTemplate_Util DATA ;
+;;SEC_NullTemplate_Util DATA ;
+;;SEC_ObjectIDTemplate_Util DATA ;
+;;SEC_OctetStringTemplate_Util DATA ;
+;;SEC_PointerToAnyTemplate_Util DATA ;
+;;SEC_PointerToEnumeratedTemplate DATA ;
+;;SEC_PointerToGeneralizedTimeTemplate DATA ;
+;;SEC_PointerToOctetStringTemplate_Util DATA ;
+;;SEC_PrintableStringTemplate DATA ;
+;;SEC_SequenceOfAnyTemplate DATA ;
+;;SEC_SequenceOfObjectIDTemplate DATA ;
+;;SEC_SetOfAnyTemplate_Util DATA ;
+;;SEC_SkipTemplate DATA ;
+;;SEC_T61StringTemplate DATA ;
+;;SEC_UniversalStringTemplate DATA ;
+;;SEC_UTF8StringTemplate_Util DATA ;
+;;SECOID_AlgorithmIDTemplate_Util DATA ;
+;;sgn_DigestInfoTemplate_Util DATA ;
+NSS_Get_SEC_AnyTemplate_Util;
+NSS_Get_SEC_BitStringTemplate_Util;
+NSS_Get_SEC_BMPStringTemplate_Util;
+NSS_Get_SEC_BooleanTemplate_Util;
+NSS_Get_SEC_EnumeratedTemplate;
+NSS_Get_SEC_GeneralizedTimeTemplate_Util;
+NSS_Get_SEC_IA5StringTemplate_Util;
+NSS_Get_SEC_IntegerTemplate_Util;
+NSS_Get_SEC_NullTemplate_Util;
+NSS_Get_SEC_ObjectIDTemplate_Util;
+NSS_Get_SEC_OctetStringTemplate_Util;
+NSS_Get_SEC_PointerToAnyTemplate_Util;
+NSS_Get_SEC_PointerToEnumeratedTemplate;
+NSS_Get_SEC_PointerToGeneralizedTimeTemplate;
+NSS_Get_SEC_PointerToOctetStringTemplate_Util;
+NSS_Get_SEC_PrintableStringTemplate;
+NSS_Get_SEC_SequenceOfAnyTemplate;
+NSS_Get_SEC_SequenceOfObjectIDTemplate;
+NSS_Get_SEC_SetOfAnyTemplate_Util;
+NSS_Get_SEC_SkipTemplate;
+NSS_Get_SEC_T61StringTemplate;
+NSS_Get_SEC_UniversalStringTemplate;
+NSS_Get_SEC_UTF8StringTemplate_Util;
+NSS_Get_SECOID_AlgorithmIDTemplate_Util;
+NSS_Get_sgn_DigestInfoTemplate_Util;
+;+ local:
+;+ *;
+;+};
diff --git a/security/nss/lib/util/nssutil.rc b/security/nss/lib/util/nssutil.rc
new file mode 100644
index 000000000..46a285cc5
--- /dev/null
+++ b/security/nss/lib/util/nssutil.rc
@@ -0,0 +1,100 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Network Security Services libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nss.h"
+#include <winver.h>
+
+#define MY_LIBNAME "nssutil"
+#define MY_FILEDESCRIPTION "NSS Utility Library"
+
+#define STRINGIZE(x) #x
+#define STRINGIZE2(x) STRINGIZE(x)
+#define NSS_VMAJOR_STR STRINGIZE2(NSS_VMAJOR)
+
+#ifdef _DEBUG
+#define MY_DEBUG_STR " (debug)"
+#define MY_FILEFLAGS_1 VS_FF_DEBUG
+#else
+#define MY_DEBUG_STR ""
+#define MY_FILEFLAGS_1 0x0L
+#endif
+#if NSS_BETA
+#define MY_FILEFLAGS_2 MY_FILEFLAGS_1|VS_FF_PRERELEASE
+#else
+#define MY_FILEFLAGS_2 MY_FILEFLAGS_1
+#endif
+
+#ifdef WINNT
+#define MY_FILEOS VOS_NT_WINDOWS32
+#else
+#define MY_FILEOS VOS__WINDOWS32
+#endif
+
+#define MY_INTERNAL_NAME MY_LIBNAME NSS_VMAJOR_STR
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Version-information resource
+//
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION NSS_VMAJOR,NSS_VMINOR,NSS_VPATCH,0
+ PRODUCTVERSION NSS_VMAJOR,NSS_VMINOR,NSS_VPATCH,0
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS MY_FILEFLAGS_2
+ FILEOS MY_FILEOS
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0x0L // not used
+
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904B0" // Lang=US English, CharSet=Unicode
+ BEGIN
+ VALUE "CompanyName", "Mozilla Foundation\0"
+ VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0"
+ VALUE "FileVersion", NSS_VERSION "\0"
+ VALUE "InternalName", MY_INTERNAL_NAME "\0"
+ VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0"
+ VALUE "ProductName", "Network Security Services\0"
+ VALUE "ProductVersion", NSS_VERSION "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/security/nss/lib/util/oidstring.c b/security/nss/lib/util/oidstring.c
new file mode 100644
index 000000000..c7ad090cc
--- /dev/null
+++ b/security/nss/lib/util/oidstring.c
@@ -0,0 +1,145 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Network Security Services.
+ *
+ * The Initial Developer of the Original Code is Nelson B Bolyard
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include <string.h>
+#include "secitem.h"
+#include "secport.h"
+#include "secerr.h"
+
+/* if to->data is not NULL, and to->len is large enough to hold the result,
+ * then the resultant OID will be copyed into to->data, and to->len will be
+ * changed to show the actual OID length.
+ * Otherwise, memory for the OID will be allocated (from the caller's
+ * PLArenaPool, if pool is non-NULL) and to->data will receive the address
+ * of the allocated data, and to->len will receive the OID length.
+ * The original value of to->data is not freed when a new buffer is allocated.
+ *
+ * The input string may begin with "OID." and this still be ignored.
+ * The length of the input string is given in len. If len == 0, then
+ * len will be computed as strlen(from), meaning it must be NUL terminated.
+ * It is an error if from == NULL, or if *from == '\0'.
+ */
+
+SECStatus
+SEC_StringToOID(PLArenaPool *pool, SECItem *to, const char *from, PRUint32 len)
+{
+ PRUint32 decimal_numbers = 0;
+ PRUint32 result_bytes = 0;
+ SECStatus rv;
+ PRUint8 result[1024];
+
+ static const PRUint32 max_decimal = (0xffffffff / 10);
+ static const char OIDstring[] = {"OID."};
+
+ if (!from || !to) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+ if (!len) {
+ len = PL_strlen(from);
+ }
+ if (len >= 4 && !PL_strncasecmp(from, OIDstring, 4)) {
+ from += 4; /* skip leading "OID." if present */
+ len -= 4;
+ }
+ if (!len) {
+bad_data:
+ PORT_SetError(SEC_ERROR_BAD_DATA);
+ return SECFailure;
+ }
+ do {
+ PRUint32 decimal = 0;
+ while (len > 0 && isdigit(*from)) {
+ PRUint32 addend = (*from++ - '0');
+ --len;
+ if (decimal > max_decimal) /* overflow */
+ goto bad_data;
+ decimal = (decimal * 10) + addend;
+ if (decimal < addend) /* overflow */
+ goto bad_data;
+ }
+ if (len != 0 && *from != '.') {
+ goto bad_data;
+ }
+ if (decimal_numbers == 0) {
+ if (decimal > 2)
+ goto bad_data;
+ result[0] = decimal * 40;
+ result_bytes = 1;
+ } else if (decimal_numbers == 1) {
+ if (decimal > 40)
+ goto bad_data;
+ result[0] += decimal;
+ } else {
+ /* encode the decimal number, */
+ PRUint8 * rp;
+ PRUint32 num_bytes = 0;
+ PRUint32 tmp = decimal;
+ while (tmp) {
+ num_bytes++;
+ tmp >>= 7;
+ }
+ if (!num_bytes )
+ ++num_bytes; /* use one byte for a zero value */
+ if (num_bytes + result_bytes > sizeof result)
+ goto bad_data;
+ tmp = num_bytes;
+ rp = result + result_bytes - 1;
+ rp[tmp] = (PRUint8)(decimal & 0x7f);
+ decimal >>= 7;
+ while (--tmp > 0) {
+ rp[tmp] = (PRUint8)(decimal | 0x80);
+ decimal >>= 7;
+ }
+ result_bytes += num_bytes;
+ }
+ ++decimal_numbers;
+ if (len > 0) { /* skip trailing '.' */
+ ++from;
+ --len;
+ }
+ } while (len > 0);
+ /* now result contains result_bytes of data */
+ if (to->data && to->len >= result_bytes) {
+ PORT_Memcpy(to->data, result, to->len = result_bytes);
+ rv = SECSuccess;
+ } else {
+ SECItem result_item = {siBuffer, NULL, 0 };
+ result_item.data = result;
+ result_item.len = result_bytes;
+ rv = SECITEM_CopyItem(pool, to, &result_item);
+ }
+ return rv;
+}
diff --git a/security/nss/lib/util/portreg.c b/security/nss/lib/util/portreg.c
new file mode 100644
index 000000000..869dab10a
--- /dev/null
+++ b/security/nss/lib/util/portreg.c
@@ -0,0 +1,321 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Ken Key <key+mozilla@ksquared.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * shexp.c: shell-like wildcard match routines
+ *
+ *
+ * See shexp.h for public documentation.
+ *
+ */
+
+#include "seccomon.h"
+#include "portreg.h"
+
+/* ----------------------------- shexp_valid ------------------------------ */
+
+
+static int
+_valid_subexp(const char *exp, char stop)
+{
+ register int x,y,t;
+ int nsc,np,tld;
+
+ x=0;nsc=0;tld=0;
+
+ while(exp[x] && (exp[x] != stop)) {
+ switch(exp[x]) {
+ case '~':
+ if(tld) return INVALID_SXP;
+ else ++tld;
+ case '*':
+ case '?':
+ case '^':
+ case '$':
+ ++nsc;
+ break;
+ case '[':
+ ++nsc;
+ if((!exp[++x]) || (exp[x] == ']'))
+ return INVALID_SXP;
+ for(++x;exp[x] && (exp[x] != ']');++x)
+ if(exp[x] == '\\')
+ if(!exp[++x])
+ return INVALID_SXP;
+ if(!exp[x])
+ return INVALID_SXP;
+ break;
+ case '(':
+ ++nsc;np = 0;
+ while(1) {
+ if(exp[++x] == ')')
+ return INVALID_SXP;
+ for(y=x;(exp[y]) && (exp[y] != '|') && (exp[y] != ')');++y)
+ if(exp[y] == '\\')
+ if(!exp[++y])
+ return INVALID_SXP;
+ if(!exp[y])
+ return INVALID_SXP;
+ if(exp[y] == '|')
+ ++np;
+ t = _valid_subexp(&exp[x],exp[y]);
+ if(t == INVALID_SXP)
+ return INVALID_SXP;
+ x+=t;
+ if(exp[x] == ')') {
+ if(!np)
+ return INVALID_SXP;
+ break;
+ }
+ }
+ break;
+ case ')':
+ case ']':
+ return INVALID_SXP;
+ case '\\':
+ if(!exp[++x])
+ return INVALID_SXP;
+ default:
+ break;
+ }
+ ++x;
+ }
+ if((!stop) && (!nsc))
+ return NON_SXP;
+ return ((exp[x] == stop) ? x : INVALID_SXP);
+}
+
+int
+PORT_RegExpValid(const char *exp)
+{
+ int x;
+
+ x = _valid_subexp(exp, '\0');
+ return (x < 0 ? x : VALID_SXP);
+}
+
+
+/* ----------------------------- shexp_match ----------------------------- */
+
+
+#define MATCH 0
+#define NOMATCH 1
+#define ABORTED -1
+
+static int _shexp_match(const char *str, const char *exp, PRBool case_insensitive);
+
+static int
+_handle_union(const char *str, const char *exp, PRBool case_insensitive)
+{
+ char *e2 = (char *) PORT_Alloc(sizeof(char)*strlen(exp));
+ register int t,p2,p1 = 1;
+ int cp;
+
+ while(1) {
+ for(cp=1;exp[cp] != ')';cp++)
+ if(exp[cp] == '\\')
+ ++cp;
+ for(p2 = 0;(exp[p1] != '|') && (p1 != cp);p1++,p2++) {
+ if(exp[p1] == '\\')
+ e2[p2++] = exp[p1++];
+ e2[p2] = exp[p1];
+ }
+ for (t=cp+1; ((e2[p2] = exp[t]) != 0); ++t,++p2) {}
+ if(_shexp_match(str,e2, case_insensitive) == MATCH) {
+ PORT_Free(e2);
+ return MATCH;
+ }
+ if(p1 == cp) {
+ PORT_Free(e2);
+ return NOMATCH;
+ }
+ else ++p1;
+ }
+}
+
+
+static int
+_shexp_match(const char *str, const char *exp, PRBool case_insensitive)
+{
+ register int x,y;
+ int ret,neg;
+
+ ret = 0;
+ for(x=0,y=0;exp[y];++y,++x) {
+ if((!str[x]) && (exp[y] != '(') && (exp[y] != '$') && (exp[y] != '*'))
+ ret = ABORTED;
+ else {
+ switch(exp[y]) {
+ case '$':
+ if( (str[x]) )
+ ret = NOMATCH;
+ else
+ --x; /* we don't want loop to increment x */
+ break;
+ case '*':
+ while(exp[++y] == '*'){}
+ if(!exp[y])
+ return MATCH;
+ while(str[x]) {
+ switch(_shexp_match(&str[x++],&exp[y], case_insensitive)) {
+ case NOMATCH:
+ continue;
+ case ABORTED:
+ ret = ABORTED;
+ break;
+ default:
+ return MATCH;
+ }
+ break;
+ }
+ if((exp[y] == '$') && (exp[y+1] == '\0') && (!str[x]))
+ return MATCH;
+ else
+ ret = ABORTED;
+ break;
+ case '[':
+ neg = ((exp[++y] == '^') && (exp[y+1] != ']'));
+ if (neg)
+ ++y;
+
+ if ((isalnum(exp[y])) && (exp[y+1] == '-') &&
+ (isalnum(exp[y+2])) && (exp[y+3] == ']'))
+ {
+ int start = exp[y], end = exp[y+2];
+
+ /* no safeguards here */
+ if(neg ^ ((str[x] < start) || (str[x] > end))) {
+ ret = NOMATCH;
+ break;
+ }
+ y+=3;
+ }
+ else {
+ int matched;
+
+ for (matched=0;exp[y] != ']';y++)
+ matched |= (str[x] == exp[y]);
+ if (neg ^ (!matched))
+ ret = NOMATCH;
+ }
+ break;
+ case '(':
+ return _handle_union(&str[x],&exp[y], case_insensitive);
+ break;
+ case '?':
+ break;
+ case '\\':
+ ++y;
+ default:
+ if(case_insensitive)
+ {
+ if(toupper(str[x]) != toupper(exp[y]))
+ ret = NOMATCH;
+ }
+ else
+ {
+ if(str[x] != exp[y])
+ ret = NOMATCH;
+ }
+ break;
+ }
+ }
+ if(ret)
+ break;
+ }
+ return (ret ? ret : (str[x] ? NOMATCH : MATCH));
+}
+
+static int
+port_RegExpMatch(const char *str, const char *xp, PRBool case_insensitive) {
+ register int x;
+ char *exp = 0;
+
+ exp = PORT_Strdup(xp);
+
+ if(!exp)
+ return 1;
+
+ for(x=strlen(exp)-1;x;--x) {
+ if((exp[x] == '~') && (exp[x-1] != '\\')) {
+ exp[x] = '\0';
+ if(_shexp_match(str,&exp[++x], case_insensitive) == MATCH)
+ goto punt;
+ break;
+ }
+ }
+ if(_shexp_match(str,exp, case_insensitive) == MATCH) {
+ PORT_Free(exp);
+ return 0;
+ }
+
+ punt:
+ PORT_Free(exp);
+ return 1;
+}
+
+
+/* ------------------------------ shexp_cmp ------------------------------- */
+
+int
+PORT_RegExpSearch(const char *str, const char *exp)
+{
+ switch(PORT_RegExpValid(exp))
+ {
+ case INVALID_SXP:
+ return -1;
+ case NON_SXP:
+ return (strcmp(exp,str) ? 1 : 0);
+ default:
+ return port_RegExpMatch(str, exp, PR_FALSE);
+ }
+}
+
+int
+PORT_RegExpCaseSearch(const char *str, const char *exp)
+{
+ switch(PORT_RegExpValid(exp))
+ {
+ case INVALID_SXP:
+ return -1;
+ case NON_SXP:
+ return (PORT_Strcasecmp(exp,str) ? 1 : 0);
+ default:
+ return port_RegExpMatch(str, exp, PR_TRUE);
+ }
+}
+
diff --git a/security/nss/lib/util/portreg.h b/security/nss/lib/util/portreg.h
new file mode 100644
index 000000000..4304acc68
--- /dev/null
+++ b/security/nss/lib/util/portreg.h
@@ -0,0 +1,97 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * shexp.h: Defines and prototypes for shell exp. match routines
+ *
+ *
+ * This routine will match a string with a shell expression. The expressions
+ * accepted are based loosely on the expressions accepted by zsh.
+ *
+ * o * matches anything
+ * o ? matches one character
+ * o \ will escape a special character
+ * o $ matches the end of the string
+ * o [abc] matches one occurence of a, b, or c. The only character that needs
+ * to be escaped in this is ], all others are not special.
+ * o [a-z] matches any character between a and z
+ * o [^az] matches any character except a or z
+ * o ~ followed by another shell expression will remove any pattern
+ * matching the shell expression from the match list
+ * o (foo|bar) will match either the substring foo, or the substring bar.
+ * These can be shell expressions as well.
+ *
+ * The public interface to these routines is documented below.
+ *
+ */
+
+#ifndef SHEXP_H
+#define SHEXP_H
+
+#include "utilrename.h"
+/*
+ * Requires that the macro MALLOC be set to a "safe" malloc that will
+ * exit if no memory is available.
+ */
+
+
+/* --------------------------- Public routines ---------------------------- */
+
+
+/*
+ * shexp_valid takes a shell expression exp as input. It returns:
+ *
+ * NON_SXP if exp is a standard string
+ * INVALID_SXP if exp is a shell expression, but invalid
+ * VALID_SXP if exp is a valid shell expression
+ */
+
+#define NON_SXP -1
+#define INVALID_SXP -2
+#define VALID_SXP 1
+
+SEC_BEGIN_PROTOS
+
+extern int PORT_RegExpValid(const char *exp);
+
+extern int PORT_RegExpSearch(const char *str, const char *exp);
+
+/* same as above but uses case insensitive search */
+extern int PORT_RegExpCaseSearch(const char *str, const char *exp);
+
+SEC_END_PROTOS
+
+#endif
diff --git a/security/nss/lib/util/quickder.c b/security/nss/lib/util/quickder.c
new file mode 100644
index 000000000..29a582147
--- /dev/null
+++ b/security/nss/lib/util/quickder.c
@@ -0,0 +1,912 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ Optimized ASN.1 DER decoder
+
+*/
+
+#include "secerr.h"
+#include "secasn1.h" /* for SEC_ASN1GetSubtemplate */
+#include "secitem.h"
+
+/*
+ * simple definite-length ASN.1 decoder
+ */
+
+static unsigned char* definite_length_decoder(const unsigned char *buf,
+ const unsigned int length,
+ unsigned int *data_length,
+ PRBool includeTag)
+{
+ unsigned char tag;
+ unsigned int used_length= 0;
+ unsigned int data_len;
+
+ if (used_length >= length)
+ {
+ return NULL;
+ }
+ tag = buf[used_length++];
+
+ /* blow out when we come to the end */
+ if (tag == 0)
+ {
+ return NULL;
+ }
+
+ if (used_length >= length)
+ {
+ return NULL;
+ }
+ data_len = buf[used_length++];
+
+ if (data_len&0x80)
+ {
+ int len_count = data_len & 0x7f;
+
+ data_len = 0;
+
+ while (len_count-- > 0)
+ {
+ if (used_length >= length)
+ {
+ return NULL;
+ }
+ data_len = (data_len << 8) | buf[used_length++];
+ }
+ }
+
+ if (data_len > (length-used_length) )
+ {
+ return NULL;
+ }
+ if (includeTag) data_len += used_length;
+
+ *data_length = data_len;
+ return ((unsigned char*)buf + (includeTag ? 0 : used_length));
+}
+
+static SECStatus GetItem(SECItem* src, SECItem* dest, PRBool includeTag)
+{
+ if ( (!src) || (!dest) || (!src->data) )
+ {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (!src->len)
+ {
+ /* reaching the end of the buffer is not an error */
+ dest->data = NULL;
+ dest->len = 0;
+ return SECSuccess;
+ }
+
+ dest->data = definite_length_decoder(src->data, src->len, &dest->len,
+ includeTag);
+ if (dest->data == NULL)
+ {
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ return SECFailure;
+ }
+ src->len -= (dest->data - src->data) + dest->len;
+ src->data = dest->data + dest->len;
+ return SECSuccess;
+}
+
+/* check if the actual component's type matches the type in the template */
+
+static SECStatus MatchComponentType(const SEC_ASN1Template* templateEntry,
+ SECItem* item, PRBool* match, void* dest)
+{
+ unsigned long kind = 0;
+ unsigned char tag = 0;
+
+ if ( (!item) || (!templateEntry) || (!match) )
+ {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (!item->len || !item->data)
+ {
+ *match = PR_FALSE;
+ return SECSuccess;
+ }
+
+ kind = templateEntry->kind;
+ tag = *(unsigned char*) item->data;
+
+ if ( ( (kind & SEC_ASN1_INLINE) ||
+ (kind & SEC_ASN1_POINTER) ) &&
+ (0 == (kind & SEC_ASN1_TAG_MASK) ) )
+ {
+ /* These cases are special because the template's "kind" does not
+ give us the information for the ASN.1 tag of the next item. It can
+ only be figured out from the subtemplate. */
+ if (!(kind & SEC_ASN1_OPTIONAL))
+ {
+ /* This is a required component. If there is a type mismatch,
+ the decoding of the subtemplate will fail, so assume this
+ is a match at the parent level and let it fail later. This
+ avoids a redundant check in matching cases */
+ *match = PR_TRUE;
+ return SECSuccess;
+ }
+ else
+ {
+ /* optional component. This is the hard case. Now we need to
+ look at the subtemplate to get the expected kind */
+ const SEC_ASN1Template* subTemplate =
+ SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
+ if (!subTemplate)
+ {
+ PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+ return SECFailure;
+ }
+ if ( (subTemplate->kind & SEC_ASN1_INLINE) ||
+ (subTemplate->kind & SEC_ASN1_POINTER) )
+ {
+ /* disallow nesting SEC_ASN1_POINTER and SEC_ASN1_INLINE,
+ otherwise you may get a false positive due to the recursion
+ optimization above that always matches the type if the
+ component is required . Nesting these should never be
+ required, so that no one should miss this ability */
+ PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+ return SECFailure;
+ }
+ return MatchComponentType(subTemplate, item, match,
+ (void*)((char*)dest + templateEntry->offset));
+ }
+ }
+
+ if (kind & SEC_ASN1_CHOICE)
+ {
+ /* we need to check the component's tag against each choice's tag */
+ /* XXX it would be nice to save the index of the choice here so that
+ DecodeChoice wouldn't have to do this again. However, due to the
+ recursivity of MatchComponentType, we don't know if we are in a
+ required or optional component, so we can't write anywhere in
+ the destination within this function */
+ unsigned choiceIndex = 1;
+ const SEC_ASN1Template* choiceEntry;
+ while ( (choiceEntry = &templateEntry[choiceIndex++]) && (choiceEntry->kind))
+ {
+ if ( (SECSuccess == MatchComponentType(choiceEntry, item, match,
+ (void*)((char*)dest + choiceEntry->offset))) &&
+ (PR_TRUE == *match) )
+ {
+ return SECSuccess;
+ }
+ }
+ /* no match, caller must decide if this is BAD DER, or not. */
+ *match = PR_FALSE;
+ return SECSuccess;
+ }
+
+ if (kind & SEC_ASN1_ANY)
+ {
+ /* SEC_ASN1_ANY always matches */
+ *match = PR_TRUE;
+ return SECSuccess;
+ }
+
+ if ( (0 == ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK)) &&
+ (!(kind & SEC_ASN1_EXPLICIT)) &&
+ ( ( (kind & SEC_ASN1_SAVE) ||
+ (kind & SEC_ASN1_SKIP) ) &&
+ (!(kind & SEC_ASN1_OPTIONAL))
+ )
+ )
+ {
+ /* when saving or skipping a required component, a type is not
+ required in the template. This is for legacy support of
+ SEC_ASN1_SAVE and SEC_ASN1_SKIP only. XXX I would like to
+ deprecate these usages and always require a type, as this
+ disables type checking, and effectively forbids us from
+ transparently ignoring optional components we aren't aware of */
+ *match = PR_TRUE;
+ return SECSuccess;
+ }
+
+ /* first, do a class check */
+ if ( (tag & SEC_ASN1_CLASS_MASK) !=
+ (((unsigned char)kind) & SEC_ASN1_CLASS_MASK) )
+ {
+#ifdef DEBUG
+ /* this is only to help debugging of the decoder in case of problems */
+ unsigned char tagclass = tag & SEC_ASN1_CLASS_MASK;
+ unsigned char expectedclass = (unsigned char)kind & SEC_ASN1_CLASS_MASK;
+ tagclass = tagclass;
+ expectedclass = expectedclass;
+#endif
+ *match = PR_FALSE;
+ return SECSuccess;
+ }
+
+ /* now do a tag check */
+ if ( ((unsigned char)kind & SEC_ASN1_TAGNUM_MASK) !=
+ (tag & SEC_ASN1_TAGNUM_MASK))
+ {
+ *match = PR_FALSE;
+ return SECSuccess;
+ }
+
+ /* now, do a method check. This depends on the class */
+ switch (tag & SEC_ASN1_CLASS_MASK)
+ {
+ case SEC_ASN1_UNIVERSAL:
+ /* For types of the SEC_ASN1_UNIVERSAL class, we know which must be
+ primitive or constructed based on the tag */
+ switch (tag & SEC_ASN1_TAGNUM_MASK)
+ {
+ case SEC_ASN1_SEQUENCE:
+ case SEC_ASN1_SET:
+ case SEC_ASN1_EMBEDDED_PDV:
+ /* this component must be a constructed type */
+ /* XXX add any new universal constructed type here */
+ if (tag & SEC_ASN1_CONSTRUCTED)
+ {
+ *match = PR_TRUE;
+ return SECSuccess;
+ }
+ break;
+
+ default:
+ /* this component must be a primitive type */
+ if (! (tag & SEC_ASN1_CONSTRUCTED))
+ {
+ *match = PR_TRUE;
+ return SECSuccess;
+ }
+ break;
+ }
+ break;
+
+ default:
+ /* for all other classes, we check the method based on the template */
+ if ( (unsigned char)(kind & SEC_ASN1_METHOD_MASK) ==
+ (tag & SEC_ASN1_METHOD_MASK) )
+ {
+ *match = PR_TRUE;
+ return SECSuccess;
+ }
+ /* method does not match between template and component */
+ break;
+ }
+
+ *match = PR_FALSE;
+ return SECSuccess;
+}
+
+#ifdef DEBUG
+
+static SECStatus CheckSequenceTemplate(const SEC_ASN1Template* sequenceTemplate)
+{
+ SECStatus rv = SECSuccess;
+ const SEC_ASN1Template* sequenceEntry = NULL;
+ unsigned long seqIndex = 0;
+ unsigned long lastEntryIndex = 0;
+ unsigned long ambiguityIndex = 0;
+ PRBool foundAmbiguity = PR_FALSE;
+
+ do
+ {
+ sequenceEntry = &sequenceTemplate[seqIndex++];
+ if (sequenceEntry->kind)
+ {
+ /* ensure that we don't have an optional component of SEC_ASN1_ANY
+ in the middle of the sequence, since we could not handle it */
+ /* XXX this function needs to dig into the subtemplates to find
+ the next tag */
+ if ( (PR_FALSE == foundAmbiguity) &&
+ (sequenceEntry->kind & SEC_ASN1_OPTIONAL) &&
+ (sequenceEntry->kind & SEC_ASN1_ANY) )
+ {
+ foundAmbiguity = PR_TRUE;
+ ambiguityIndex = seqIndex - 1;
+ }
+ }
+ } while (sequenceEntry->kind);
+
+ lastEntryIndex = seqIndex - 2;
+
+ if (PR_FALSE != foundAmbiguity)
+ {
+ if (ambiguityIndex < lastEntryIndex)
+ {
+ /* ambiguity can only be tolerated on the last entry */
+ PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+ rv = SECFailure;
+ }
+ }
+
+ /* XXX also enforce ASN.1 requirement that tags be
+ distinct for consecutive optional components */
+
+ return rv;
+}
+
+#endif
+
+static SECStatus DecodeItem(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena, PRBool checkTag);
+
+static SECStatus DecodeSequence(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena)
+{
+ SECStatus rv = SECSuccess;
+ SECItem source;
+ SECItem sequence;
+ const SEC_ASN1Template* sequenceTemplate = &(templateEntry[1]);
+ const SEC_ASN1Template* sequenceEntry = NULL;
+ unsigned long seqindex = 0;
+
+#ifdef DEBUG
+ /* for a sequence, we need to validate the template. */
+ rv = CheckSequenceTemplate(sequenceTemplate);
+#endif
+
+ source = *src;
+
+ /* get the sequence */
+ if (SECSuccess == rv)
+ {
+ rv = GetItem(&source, &sequence, PR_FALSE);
+ }
+
+ /* process it */
+ if (SECSuccess == rv)
+ do
+ {
+ sequenceEntry = &sequenceTemplate[seqindex++];
+ if ( (sequenceEntry && sequenceEntry->kind) &&
+ (sequenceEntry->kind != SEC_ASN1_SKIP_REST) )
+ {
+ rv = DecodeItem(dest, sequenceEntry, &sequence, arena, PR_TRUE);
+ }
+ } while ( (SECSuccess == rv) &&
+ (sequenceEntry->kind &&
+ sequenceEntry->kind != SEC_ASN1_SKIP_REST) );
+ /* we should have consumed all the bytes in the sequence by now
+ unless the caller doesn't care about the rest of the sequence */
+ if (SECSuccess == rv && sequence.len &&
+ sequenceEntry && sequenceEntry->kind != SEC_ASN1_SKIP_REST)
+ {
+ /* it isn't 100% clear whether this is a bad DER or a bad template.
+ The problem is that logically, they don't match - there is extra
+ data in the DER that the template doesn't know about */
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ rv = SECFailure;
+ }
+
+ return rv;
+}
+
+static SECStatus DecodeInline(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena, PRBool checkTag)
+{
+ const SEC_ASN1Template* inlineTemplate =
+ SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
+ return DecodeItem((void*)((char*)dest + templateEntry->offset),
+ inlineTemplate, src, arena, checkTag);
+}
+
+static SECStatus DecodePointer(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena, PRBool checkTag)
+{
+ const SEC_ASN1Template* ptrTemplate =
+ SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
+ void* subdata = PORT_ArenaZAlloc(arena, ptrTemplate->size);
+ *(void**)((char*)dest + templateEntry->offset) = subdata;
+ if (subdata)
+ {
+ return DecodeItem(subdata, ptrTemplate, src, arena, checkTag);
+ }
+ else
+ {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return SECFailure;
+ }
+}
+
+static SECStatus DecodeImplicit(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena)
+{
+ if (templateEntry->kind & SEC_ASN1_POINTER)
+ {
+ return DecodePointer((void*)((char*)dest ),
+ templateEntry, src, arena, PR_FALSE);
+ }
+ else
+ {
+ return DecodeInline((void*)((char*)dest ),
+ templateEntry, src, arena, PR_FALSE);
+ }
+}
+
+static SECStatus DecodeChoice(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena)
+{
+ SECStatus rv = SECSuccess;
+ SECItem choice;
+ const SEC_ASN1Template* choiceTemplate = &(templateEntry[1]);
+ const SEC_ASN1Template* choiceEntry = NULL;
+ unsigned long choiceindex = 0;
+
+ /* XXX for a choice component, we should validate the template to make
+ sure the tags are distinct, in debug builds. This hasn't been
+ implemented yet */
+ /* rv = CheckChoiceTemplate(sequenceTemplate); */
+
+ /* process it */
+ do
+ {
+ choice = *src;
+ choiceEntry = &choiceTemplate[choiceindex++];
+ if (choiceEntry->kind)
+ {
+ rv = DecodeItem(dest, choiceEntry, &choice, arena, PR_TRUE);
+ }
+ } while ( (SECFailure == rv) && (choiceEntry->kind));
+
+ if (SECFailure == rv)
+ {
+ /* the component didn't match any of the choices */
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ }
+ else
+ {
+ /* set the type in the union here */
+ int *which = (int *)((char *)dest + templateEntry->offset);
+ *which = (int)choiceEntry->size;
+ }
+
+ /* we should have consumed all the bytes by now */
+ /* fail if we have not */
+ if (SECSuccess == rv && choice.len)
+ {
+ /* there is extra data that isn't listed in the template */
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ rv = SECFailure;
+ }
+ return rv;
+}
+
+static SECStatus DecodeGroup(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena)
+{
+ SECStatus rv = SECSuccess;
+ SECItem source;
+ SECItem group;
+ PRUint32 totalEntries = 0;
+ PRUint32 entryIndex = 0;
+ void** entries = NULL;
+
+ const SEC_ASN1Template* subTemplate =
+ SEC_ASN1GetSubtemplate (templateEntry, dest, PR_FALSE);
+
+ source = *src;
+
+ /* get the group */
+ if (SECSuccess == rv)
+ {
+ rv = GetItem(&source, &group, PR_FALSE);
+ }
+
+ /* XXX we should check the subtemplate in debug builds */
+ if (SECSuccess == rv)
+ {
+ /* first, count the number of entries. Benchmarking showed that this
+ counting pass is more efficient than trying to allocate entries as
+ we read the DER, even if allocating many entries at a time
+ */
+ SECItem counter = group;
+ do
+ {
+ SECItem anitem;
+ rv = GetItem(&counter, &anitem, PR_TRUE);
+ if (SECSuccess == rv && (anitem.len) )
+ {
+ totalEntries++;
+ }
+ } while ( (SECSuccess == rv) && (counter.len) );
+
+ if (SECSuccess == rv)
+ {
+ /* allocate room for pointer array and entries */
+ /* we want to allocate the array even if there is 0 entry */
+ entries = (void**)PORT_ArenaZAlloc(arena, sizeof(void*)*
+ (totalEntries + 1 ) + /* the extra one is for NULL termination */
+ subTemplate->size*totalEntries);
+
+ if (entries)
+ {
+ entries[totalEntries] = NULL; /* terminate the array */
+ }
+ else
+ {
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ rv = SECFailure;
+ }
+ if (SECSuccess == rv)
+ {
+ void* entriesData = (unsigned char*)entries + (unsigned long)(sizeof(void*)*(totalEntries + 1 ));
+ /* and fix the pointers in the array */
+ PRUint32 entriesIndex = 0;
+ for (entriesIndex = 0;entriesIndex<totalEntries;entriesIndex++)
+ {
+ entries[entriesIndex] =
+ (char*)entriesData + (subTemplate->size*entriesIndex);
+ }
+ }
+ }
+ }
+
+ if (SECSuccess == rv && totalEntries)
+ do
+ {
+ if (!(entryIndex<totalEntries))
+ {
+ rv = SECFailure;
+ break;
+ }
+ rv = DecodeItem(entries[entryIndex++], subTemplate, &group, arena, PR_TRUE);
+ } while ( (SECSuccess == rv) && (group.len) );
+ /* we should be at the end of the set by now */
+ /* save the entries where requested */
+ memcpy(((char*)dest + templateEntry->offset), &entries, sizeof(void**));
+
+ return rv;
+}
+
+static SECStatus DecodeExplicit(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena)
+{
+ SECStatus rv = SECSuccess;
+ SECItem subItem;
+ SECItem constructed = *src;
+
+ rv = GetItem(&constructed, &subItem, PR_FALSE);
+
+ if (SECSuccess == rv)
+ {
+ if (templateEntry->kind & SEC_ASN1_POINTER)
+ {
+ rv = DecodePointer(dest, templateEntry, &subItem, arena, PR_TRUE);
+ }
+ else
+ {
+ rv = DecodeInline(dest, templateEntry, &subItem, arena, PR_TRUE);
+ }
+ }
+
+ return rv;
+}
+
+/* new decoder implementation. This is a recursive function */
+
+static SECStatus DecodeItem(void* dest,
+ const SEC_ASN1Template* templateEntry,
+ SECItem* src, PRArenaPool* arena, PRBool checkTag)
+{
+ SECStatus rv = SECSuccess;
+ SECItem temp;
+ SECItem mark;
+ PRBool pop = PR_FALSE;
+ PRBool decode = PR_TRUE;
+ PRBool save = PR_FALSE;
+ unsigned long kind;
+ PRBool match = PR_TRUE;
+ PRBool optional = PR_FALSE;
+
+ PR_ASSERT(src && dest && templateEntry && arena);
+#if 0
+ if (!src || !dest || !templateEntry || !arena)
+ {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ }
+#endif
+
+ if (SECSuccess == rv)
+ {
+ /* do the template validation */
+ kind = templateEntry->kind;
+ optional = (0 != (kind & SEC_ASN1_OPTIONAL));
+ if (!kind)
+ {
+ PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+ rv = SECFailure;
+ }
+ }
+
+ if (SECSuccess == rv)
+ {
+#ifdef DEBUG
+ if (kind & SEC_ASN1_DEBUG_BREAK)
+ {
+ /* when debugging the decoder or a template that fails to
+ decode, put SEC_ASN1_DEBUG in the component that gives you
+ trouble. The decoder will then get to this block and assert.
+ If you want to debug the rest of the code, you can set a
+ breakpoint and set dontassert to PR_TRUE, which will let
+ you skip over the assert and continue the debugging session
+ past it. */
+ PRBool dontassert = PR_FALSE;
+ PR_ASSERT(dontassert); /* set bkpoint here & set dontassert*/
+ }
+#endif
+
+ if ((kind & SEC_ASN1_SKIP) ||
+ (kind & SEC_ASN1_SAVE))
+ {
+ /* if skipping or saving this component, don't decode it */
+ decode = PR_FALSE;
+ }
+
+ if (kind & (SEC_ASN1_SAVE | SEC_ASN1_OPTIONAL))
+ {
+ /* if saving this component, or if it is optional, we may not want to
+ move past it, so save the position in case we have to rewind */
+ mark = *src;
+ if (kind & SEC_ASN1_SAVE)
+ {
+ save = PR_TRUE;
+ if (0 == (kind & SEC_ASN1_SKIP))
+ {
+ /* we will for sure have to rewind when saving this
+ component and not skipping it. This is true for all
+ legacy uses of SEC_ASN1_SAVE where the following entry
+ in the template would causes the same component to be
+ processed again */
+ pop = PR_TRUE;
+ }
+ }
+ }
+
+ rv = GetItem(src, &temp, PR_TRUE);
+ }
+
+ if (SECSuccess == rv)
+ {
+ /* now check if the component matches what we expect in the template */
+
+ if (PR_TRUE == checkTag)
+
+ {
+ rv = MatchComponentType(templateEntry, &temp, &match, dest);
+ }
+
+ if ( (SECSuccess == rv) && (PR_TRUE != match) )
+ {
+ if (kind & SEC_ASN1_OPTIONAL)
+ {
+
+ /* the optional component is missing. This is not fatal. */
+ /* Rewind, don't decode, and don't save */
+ pop = PR_TRUE;
+ decode = PR_FALSE;
+ save = PR_FALSE;
+ }
+ else
+ {
+ /* a required component is missing. abort */
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ rv = SECFailure;
+ }
+ }
+ }
+
+ if ((SECSuccess == rv) && (PR_TRUE == decode))
+ {
+ /* the order of processing here is is the tricky part */
+ /* we start with our special cases */
+ /* first, check the component class */
+ if (kind & SEC_ASN1_INLINE)
+ {
+ /* decode inline template */
+ rv = DecodeInline(dest, templateEntry, &temp , arena, PR_TRUE);
+ }
+
+ else
+ if (kind & SEC_ASN1_EXPLICIT)
+ {
+ rv = DecodeExplicit(dest, templateEntry, &temp, arena);
+ }
+ else
+ if ( (SEC_ASN1_UNIVERSAL != (kind & SEC_ASN1_CLASS_MASK)) &&
+
+ (!(kind & SEC_ASN1_EXPLICIT)))
+ {
+
+ /* decode implicitly tagged components */
+ rv = DecodeImplicit(dest, templateEntry, &temp , arena);
+ }
+ else
+ if (kind & SEC_ASN1_POINTER)
+ {
+ rv = DecodePointer(dest, templateEntry, &temp, arena, PR_TRUE);
+ }
+ else
+ if (kind & SEC_ASN1_CHOICE)
+ {
+ rv = DecodeChoice(dest, templateEntry, &temp, arena);
+ }
+ else
+ if (kind & SEC_ASN1_ANY)
+ {
+ /* catch-all ANY type, don't decode */
+ save = PR_TRUE;
+ if (kind & SEC_ASN1_INNER)
+ {
+ /* skip the tag and length */
+ SECItem newtemp = temp;
+ rv = GetItem(&newtemp, &temp, PR_FALSE);
+ }
+ }
+ else
+ if (kind & SEC_ASN1_GROUP)
+ {
+ if ( (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK)) ||
+ (SEC_ASN1_SET == (kind & SEC_ASN1_TAGNUM_MASK)) )
+ {
+ rv = DecodeGroup(dest, templateEntry, &temp , arena);
+ }
+ else
+ {
+ /* a group can only be a SET OF or SEQUENCE OF */
+ PORT_SetError(SEC_ERROR_BAD_TEMPLATE);
+ rv = SECFailure;
+ }
+ }
+ else
+ if (SEC_ASN1_SEQUENCE == (kind & SEC_ASN1_TAGNUM_MASK))
+ {
+ /* plain SEQUENCE */
+ rv = DecodeSequence(dest, templateEntry, &temp , arena);
+ }
+ else
+ {
+ /* handle all other types as "save" */
+ /* we should only get here for primitive universal types */
+ SECItem newtemp = temp;
+ rv = GetItem(&newtemp, &temp, PR_FALSE);
+ save = PR_TRUE;
+ if ((SECSuccess == rv) && SEC_ASN1_UNIVERSAL == (kind & SEC_ASN1_CLASS_MASK))
+ switch (kind & SEC_ASN1_TAGNUM_MASK)
+ {
+ /* special cases of primitive types */
+ case SEC_ASN1_INTEGER:
+ {
+ /* remove leading zeroes if the caller requested siUnsignedInteger
+ This is to allow RSA key operations to work */
+ SECItem* destItem = (SECItem*) ((char*)dest + templateEntry->offset);
+ if (destItem && (siUnsignedInteger == destItem->type))
+ {
+ while (temp.len > 1 && temp.data[0] == 0)
+ { /* leading 0 */
+ temp.data++;
+ temp.len--;
+ }
+ }
+ break;
+ }
+
+ case SEC_ASN1_BIT_STRING:
+ {
+ /* change the length in the SECItem to be the number of bits */
+ if (temp.len && temp.data)
+ {
+ temp.len = (temp.len-1)*8 - ((*(unsigned char*)temp.data) & 0x7);
+ temp.data = (unsigned char*)(temp.data+1);
+ }
+ break;
+ }
+
+ default:
+ {
+ break;
+ }
+ }
+ }
+ }
+
+ if ((SECSuccess == rv) && (PR_TRUE == save))
+ {
+ SECItem* destItem = (SECItem*) ((char*)dest + templateEntry->offset);
+ if (destItem)
+ {
+ /* we leave the type alone in the destination SECItem.
+ If part of the destination was allocated by the decoder, in
+ cases of POINTER, SET OF and SEQUENCE OF, then type is set to
+ siBuffer due to the use of PORT_ArenaZAlloc*/
+ destItem->data = temp.data;
+ destItem->len = temp.len;
+ }
+ else
+ {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ }
+ }
+
+ if (PR_TRUE == pop)
+ {
+ /* we don't want to move ahead, so restore the position */
+ *src = mark;
+ }
+ return rv;
+}
+
+/* the function below is the public one */
+
+SECStatus SEC_QuickDERDecodeItem(PRArenaPool* arena, void* dest,
+ const SEC_ASN1Template* templateEntry,
+ const SECItem* src)
+{
+ SECStatus rv = SECSuccess;
+ SECItem newsrc;
+
+ if (!arena || !templateEntry || !src)
+ {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ rv = SECFailure;
+ }
+
+ if (SECSuccess == rv)
+ {
+ newsrc = *src;
+ rv = DecodeItem(dest, templateEntry, &newsrc, arena, PR_TRUE);
+ if (SECSuccess == rv && newsrc.len)
+ {
+ rv = SECFailure;
+ PORT_SetError(SEC_ERROR_EXTRA_INPUT);
+ }
+ }
+
+ return rv;
+}
+
diff --git a/security/nss/lib/util/secalgid.c b/security/nss/lib/util/secalgid.c
new file mode 100644
index 000000000..dc6c56396
--- /dev/null
+++ b/security/nss/lib/util/secalgid.c
@@ -0,0 +1,157 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "secoid.h"
+#include "secder.h" /* XXX remove this when remove the DERTemplate */
+#include "secasn1.h"
+#include "secitem.h"
+#include "secerr.h"
+
+SECOidTag
+SECOID_GetAlgorithmTag(SECAlgorithmID *id)
+{
+ if (id == NULL || id->algorithm.data == NULL)
+ return SEC_OID_UNKNOWN;
+
+ return SECOID_FindOIDTag (&(id->algorithm));
+}
+
+SECStatus
+SECOID_SetAlgorithmID(PRArenaPool *arena, SECAlgorithmID *id, SECOidTag which,
+ SECItem *params)
+{
+ SECOidData *oiddata;
+ PRBool add_null_param;
+
+ oiddata = SECOID_FindOIDByTag(which);
+ if ( !oiddata ) {
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+ return SECFailure;
+ }
+
+ if (SECITEM_CopyItem(arena, &id->algorithm, &oiddata->oid))
+ return SECFailure;
+
+ switch (which) {
+ case SEC_OID_MD2:
+ case SEC_OID_MD4:
+ case SEC_OID_MD5:
+ case SEC_OID_SHA1:
+ case SEC_OID_SHA256:
+ case SEC_OID_SHA384:
+ case SEC_OID_SHA512:
+ case SEC_OID_PKCS1_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION:
+ case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION:
+ add_null_param = PR_TRUE;
+ break;
+ default:
+ add_null_param = PR_FALSE;
+ break;
+ }
+
+ if (params) {
+ /*
+ * I am specifically *not* enforcing the following assertion
+ * (by following it up with an error and a return of failure)
+ * because I do not want to introduce any change in the current
+ * behavior. But I do want for us to notice if the following is
+ * ever true, because I do not think it should be so and probably
+ * signifies an error/bug somewhere.
+ */
+ PORT_Assert(!add_null_param || (params->len == 2
+ && params->data[0] == SEC_ASN1_NULL
+ && params->data[1] == 0));
+ if (SECITEM_CopyItem(arena, &id->parameters, params)) {
+ return SECFailure;
+ }
+ } else {
+ /*
+ * Again, this is not considered an error. But if we assume
+ * that nobody tries to set the parameters field themselves
+ * (but always uses this routine to do that), then we should
+ * not hit the following assertion. Unless they forgot to zero
+ * the structure, which could also be a bad (and wrong) thing.
+ */
+ PORT_Assert(id->parameters.data == NULL);
+
+ if (add_null_param) {
+ (void) SECITEM_AllocItem(arena, &id->parameters, 2);
+ if (id->parameters.data == NULL) {
+ return SECFailure;
+ }
+ id->parameters.data[0] = SEC_ASN1_NULL;
+ id->parameters.data[1] = 0;
+ }
+ }
+
+ return SECSuccess;
+}
+
+SECStatus
+SECOID_CopyAlgorithmID(PRArenaPool *arena, SECAlgorithmID *to, SECAlgorithmID *from)
+{
+ SECStatus rv;
+
+ rv = SECITEM_CopyItem(arena, &to->algorithm, &from->algorithm);
+ if (rv) return rv;
+ rv = SECITEM_CopyItem(arena, &to->parameters, &from->parameters);
+ return rv;
+}
+
+void SECOID_DestroyAlgorithmID(SECAlgorithmID *algid, PRBool freeit)
+{
+ SECITEM_FreeItem(&algid->parameters, PR_FALSE);
+ SECITEM_FreeItem(&algid->algorithm, PR_FALSE);
+ if(freeit == PR_TRUE)
+ PORT_Free(algid);
+}
+
+SECComparison
+SECOID_CompareAlgorithmID(SECAlgorithmID *a, SECAlgorithmID *b)
+{
+ SECComparison rv;
+
+ rv = SECITEM_CompareItem(&a->algorithm, &b->algorithm);
+ if (rv) return rv;
+ rv = SECITEM_CompareItem(&a->parameters, &b->parameters);
+ return rv;
+}
diff --git a/security/nss/lib/util/secasn1.h b/security/nss/lib/util/secasn1.h
new file mode 100644
index 000000000..bda6cdd8a
--- /dev/null
+++ b/security/nss/lib/util/secasn1.h
@@ -0,0 +1,320 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Support for encoding/decoding of ASN.1 using BER/DER (Basic/Distinguished
+ * Encoding Rules). The routines are found in and used extensively by the
+ * security library, but exported for other use.
+ *
+ * $Id$
+ */
+
+#ifndef _SECASN1_H_
+#define _SECASN1_H_
+
+#include "utilrename.h"
+#include "plarena.h"
+
+#include "seccomon.h"
+#include "secasn1t.h"
+
+
+/************************************************************************/
+SEC_BEGIN_PROTOS
+
+/*
+ * XXX These function prototypes need full, explanatory comments.
+ */
+
+/*
+** Decoding.
+*/
+
+extern SEC_ASN1DecoderContext *SEC_ASN1DecoderStart(PLArenaPool *pool,
+ void *dest,
+ const SEC_ASN1Template *t);
+
+/* XXX char or unsigned char? */
+extern SECStatus SEC_ASN1DecoderUpdate(SEC_ASN1DecoderContext *cx,
+ const char *buf,
+ unsigned long len);
+
+extern SECStatus SEC_ASN1DecoderFinish(SEC_ASN1DecoderContext *cx);
+
+/* Higher level code detected an error, abort the rest of the processing */
+extern void SEC_ASN1DecoderAbort(SEC_ASN1DecoderContext *cx, int error);
+
+extern void SEC_ASN1DecoderSetFilterProc(SEC_ASN1DecoderContext *cx,
+ SEC_ASN1WriteProc fn,
+ void *arg, PRBool no_store);
+
+extern void SEC_ASN1DecoderClearFilterProc(SEC_ASN1DecoderContext *cx);
+
+extern void SEC_ASN1DecoderSetNotifyProc(SEC_ASN1DecoderContext *cx,
+ SEC_ASN1NotifyProc fn,
+ void *arg);
+
+extern void SEC_ASN1DecoderClearNotifyProc(SEC_ASN1DecoderContext *cx);
+
+extern SECStatus SEC_ASN1Decode(PLArenaPool *pool, void *dest,
+ const SEC_ASN1Template *t,
+ const char *buf, long len);
+
+/* Both classic ASN.1 and QuickDER have a feature that removes leading zeroes
+ out of SEC_ASN1_INTEGER if the caller sets siUnsignedInteger in the type
+ field of the target SECItem prior to calling the decoder. Otherwise, the
+ type field is ignored and untouched. For SECItem that are dynamically
+ allocated (from POINTER, SET OF, SEQUENCE OF) the decoder sets the type
+ field to siBuffer. */
+
+extern SECStatus SEC_ASN1DecodeItem(PLArenaPool *pool, void *dest,
+ const SEC_ASN1Template *t,
+ const SECItem *src);
+
+extern SECStatus SEC_QuickDERDecodeItem(PLArenaPool* arena, void* dest,
+ const SEC_ASN1Template* templateEntry,
+ const SECItem* src);
+
+/*
+** Encoding.
+*/
+
+extern SEC_ASN1EncoderContext *SEC_ASN1EncoderStart(const void *src,
+ const SEC_ASN1Template *t,
+ SEC_ASN1WriteProc fn,
+ void *output_arg);
+
+/* XXX char or unsigned char? */
+extern SECStatus SEC_ASN1EncoderUpdate(SEC_ASN1EncoderContext *cx,
+ const char *buf,
+ unsigned long len);
+
+extern void SEC_ASN1EncoderFinish(SEC_ASN1EncoderContext *cx);
+
+/* Higher level code detected an error, abort the rest of the processing */
+extern void SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext *cx, int error);
+
+extern void SEC_ASN1EncoderSetNotifyProc(SEC_ASN1EncoderContext *cx,
+ SEC_ASN1NotifyProc fn,
+ void *arg);
+
+extern void SEC_ASN1EncoderClearNotifyProc(SEC_ASN1EncoderContext *cx);
+
+extern void SEC_ASN1EncoderSetStreaming(SEC_ASN1EncoderContext *cx);
+
+extern void SEC_ASN1EncoderClearStreaming(SEC_ASN1EncoderContext *cx);
+
+extern void sec_ASN1EncoderSetDER(SEC_ASN1EncoderContext *cx);
+
+extern void sec_ASN1EncoderClearDER(SEC_ASN1EncoderContext *cx);
+
+extern void SEC_ASN1EncoderSetTakeFromBuf(SEC_ASN1EncoderContext *cx);
+
+extern void SEC_ASN1EncoderClearTakeFromBuf(SEC_ASN1EncoderContext *cx);
+
+extern SECStatus SEC_ASN1Encode(const void *src, const SEC_ASN1Template *t,
+ SEC_ASN1WriteProc output_proc,
+ void *output_arg);
+
+extern SECItem * SEC_ASN1EncodeItem(PLArenaPool *pool, SECItem *dest,
+ const void *src, const SEC_ASN1Template *t);
+
+extern SECItem * SEC_ASN1EncodeInteger(PLArenaPool *pool,
+ SECItem *dest, long value);
+
+extern SECItem * SEC_ASN1EncodeUnsignedInteger(PLArenaPool *pool,
+ SECItem *dest,
+ unsigned long value);
+
+extern SECStatus SEC_ASN1DecodeInteger(SECItem *src,
+ unsigned long *value);
+
+/*
+** Utilities.
+*/
+
+/*
+ * We have a length that needs to be encoded; how many bytes will the
+ * encoding take?
+ */
+extern int SEC_ASN1LengthLength (unsigned long len);
+
+/* encode the length and return the number of bytes we encoded. Buffer
+ * must be pre allocated */
+extern int SEC_ASN1EncodeLength(unsigned char *buf,int value);
+
+/*
+ * Find the appropriate subtemplate for the given template.
+ * This may involve calling a "chooser" function, or it may just
+ * be right there. In either case, it is expected to *have* a
+ * subtemplate; this is asserted in debug builds (in non-debug
+ * builds, NULL will be returned).
+ *
+ * "thing" is a pointer to the structure being encoded/decoded
+ * "encoding", when true, means that we are in the process of encoding
+ * (as opposed to in the process of decoding)
+ */
+extern const SEC_ASN1Template *
+SEC_ASN1GetSubtemplate (const SEC_ASN1Template *inTemplate, void *thing,
+ PRBool encoding);
+
+/* whether the template is for a primitive type or a choice of
+ * primitive types
+ */
+extern PRBool SEC_ASN1IsTemplateSimple(const SEC_ASN1Template *theTemplate);
+
+/************************************************************************/
+
+/*
+ * Generic Templates
+ * One for each of the simple types, plus a special one for ANY, plus:
+ * - a pointer to each one of those
+ * - a set of each one of those
+ * - a sequence of each one of those
+ *
+ * Note that these are alphabetical (case insensitive); please add new
+ * ones in the appropriate place.
+ */
+
+extern const SEC_ASN1Template SEC_AnyTemplate[];
+extern const SEC_ASN1Template SEC_BitStringTemplate[];
+extern const SEC_ASN1Template SEC_BMPStringTemplate[];
+extern const SEC_ASN1Template SEC_BooleanTemplate[];
+extern const SEC_ASN1Template SEC_EnumeratedTemplate[];
+extern const SEC_ASN1Template SEC_GeneralizedTimeTemplate[];
+extern const SEC_ASN1Template SEC_IA5StringTemplate[];
+extern const SEC_ASN1Template SEC_IntegerTemplate[];
+extern const SEC_ASN1Template SEC_NullTemplate[];
+extern const SEC_ASN1Template SEC_ObjectIDTemplate[];
+extern const SEC_ASN1Template SEC_OctetStringTemplate[];
+extern const SEC_ASN1Template SEC_PrintableStringTemplate[];
+extern const SEC_ASN1Template SEC_T61StringTemplate[];
+extern const SEC_ASN1Template SEC_UniversalStringTemplate[];
+extern const SEC_ASN1Template SEC_UTCTimeTemplate[];
+extern const SEC_ASN1Template SEC_UTF8StringTemplate[];
+extern const SEC_ASN1Template SEC_VisibleStringTemplate[];
+
+extern const SEC_ASN1Template SEC_PointerToAnyTemplate[];
+extern const SEC_ASN1Template SEC_PointerToBitStringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToBMPStringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToBooleanTemplate[];
+extern const SEC_ASN1Template SEC_PointerToEnumeratedTemplate[];
+extern const SEC_ASN1Template SEC_PointerToGeneralizedTimeTemplate[];
+extern const SEC_ASN1Template SEC_PointerToIA5StringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToIntegerTemplate[];
+extern const SEC_ASN1Template SEC_PointerToNullTemplate[];
+extern const SEC_ASN1Template SEC_PointerToObjectIDTemplate[];
+extern const SEC_ASN1Template SEC_PointerToOctetStringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToPrintableStringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToT61StringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToUniversalStringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToUTCTimeTemplate[];
+extern const SEC_ASN1Template SEC_PointerToUTF8StringTemplate[];
+extern const SEC_ASN1Template SEC_PointerToVisibleStringTemplate[];
+
+extern const SEC_ASN1Template SEC_SequenceOfAnyTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfBitStringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfBMPStringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfBooleanTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfEnumeratedTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfGeneralizedTimeTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfIA5StringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfIntegerTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfNullTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfObjectIDTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfOctetStringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfPrintableStringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfT61StringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfUniversalStringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfUTCTimeTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfUTF8StringTemplate[];
+extern const SEC_ASN1Template SEC_SequenceOfVisibleStringTemplate[];
+
+extern const SEC_ASN1Template SEC_SetOfAnyTemplate[];
+extern const SEC_ASN1Template SEC_SetOfBitStringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfBMPStringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfBooleanTemplate[];
+extern const SEC_ASN1Template SEC_SetOfEnumeratedTemplate[];
+extern const SEC_ASN1Template SEC_SetOfGeneralizedTimeTemplate[];
+extern const SEC_ASN1Template SEC_SetOfIA5StringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfIntegerTemplate[];
+extern const SEC_ASN1Template SEC_SetOfNullTemplate[];
+extern const SEC_ASN1Template SEC_SetOfObjectIDTemplate[];
+extern const SEC_ASN1Template SEC_SetOfOctetStringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfPrintableStringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfT61StringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfUniversalStringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfUTCTimeTemplate[];
+extern const SEC_ASN1Template SEC_SetOfUTF8StringTemplate[];
+extern const SEC_ASN1Template SEC_SetOfVisibleStringTemplate[];
+
+/*
+ * Template for skipping a subitem; this only makes sense when decoding.
+ */
+extern const SEC_ASN1Template SEC_SkipTemplate[];
+
+/* These functions simply return the address of the above-declared templates.
+** This is necessary for Windows DLLs. Sigh.
+*/
+SEC_ASN1_CHOOSER_DECLARE(SEC_AnyTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_BMPStringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_BooleanTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_BitStringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_GeneralizedTimeTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_IA5StringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_IntegerTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_NullTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_ObjectIDTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_OctetStringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_UTCTimeTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_UTF8StringTemplate)
+
+SEC_ASN1_CHOOSER_DECLARE(SEC_PointerToAnyTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_PointerToOctetStringTemplate)
+
+SEC_ASN1_CHOOSER_DECLARE(SEC_SetOfAnyTemplate)
+
+SEC_ASN1_CHOOSER_DECLARE(SEC_EnumeratedTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_PointerToEnumeratedTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_SequenceOfAnyTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_SequenceOfObjectIDTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_SkipTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_UniversalStringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_PrintableStringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_T61StringTemplate)
+SEC_ASN1_CHOOSER_DECLARE(SEC_PointerToGeneralizedTimeTemplate)
+SEC_END_PROTOS
+#endif /* _SECASN1_H_ */
diff --git a/security/nss/lib/util/secasn1d.c b/security/nss/lib/util/secasn1d.c
new file mode 100644
index 000000000..8f9364318
--- /dev/null
+++ b/security/nss/lib/util/secasn1d.c
@@ -0,0 +1,3273 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Support for DEcoding ASN.1 data based on BER/DER (Basic/Distinguished
+ * Encoding Rules).
+ *
+ * $Id$
+ */
+
+/* #define DEBUG_ASN1D_STATES 1 */
+
+#ifdef DEBUG_ASN1D_STATES
+#include <stdio.h>
+#define PR_Assert sec_asn1d_Assert
+#endif
+
+#include "secasn1.h"
+#include "secerr.h"
+
+typedef enum {
+ beforeIdentifier,
+ duringIdentifier,
+ afterIdentifier,
+ beforeLength,
+ duringLength,
+ afterLength,
+ beforeBitString,
+ duringBitString,
+ duringConstructedString,
+ duringGroup,
+ duringLeaf,
+ duringSaveEncoding,
+ duringSequence,
+ afterConstructedString,
+ afterGroup,
+ afterExplicit,
+ afterImplicit,
+ afterInline,
+ afterPointer,
+ afterSaveEncoding,
+ beforeEndOfContents,
+ duringEndOfContents,
+ afterEndOfContents,
+ beforeChoice,
+ duringChoice,
+ afterChoice,
+ notInUse
+} sec_asn1d_parse_place;
+
+#ifdef DEBUG_ASN1D_STATES
+static const char * const place_names[] = {
+ "beforeIdentifier",
+ "duringIdentifier",
+ "afterIdentifier",
+ "beforeLength",
+ "duringLength",
+ "afterLength",
+ "beforeBitString",
+ "duringBitString",
+ "duringConstructedString",
+ "duringGroup",
+ "duringLeaf",
+ "duringSaveEncoding",
+ "duringSequence",
+ "afterConstructedString",
+ "afterGroup",
+ "afterExplicit",
+ "afterImplicit",
+ "afterInline",
+ "afterPointer",
+ "afterSaveEncoding",
+ "beforeEndOfContents",
+ "duringEndOfContents",
+ "afterEndOfContents",
+ "beforeChoice",
+ "duringChoice",
+ "afterChoice",
+ "notInUse"
+};
+
+static const char * const class_names[] = {
+ "UNIVERSAL",
+ "APPLICATION",
+ "CONTEXT_SPECIFIC",
+ "PRIVATE"
+};
+
+static const char * const method_names[] = { "PRIMITIVE", "CONSTRUCTED" };
+
+static const char * const type_names[] = {
+ "END_OF_CONTENTS",
+ "BOOLEAN",
+ "INTEGER",
+ "BIT_STRING",
+ "OCTET_STRING",
+ "NULL",
+ "OBJECT_ID",
+ "OBJECT_DESCRIPTOR",
+ "(type 08)",
+ "REAL",
+ "ENUMERATED",
+ "EMBEDDED",
+ "UTF8_STRING",
+ "(type 0d)",
+ "(type 0e)",
+ "(type 0f)",
+ "SEQUENCE",
+ "SET",
+ "NUMERIC_STRING",
+ "PRINTABLE_STRING",
+ "T61_STRING",
+ "VIDEOTEXT_STRING",
+ "IA5_STRING",
+ "UTC_TIME",
+ "GENERALIZED_TIME",
+ "GRAPHIC_STRING",
+ "VISIBLE_STRING",
+ "GENERAL_STRING",
+ "UNIVERSAL_STRING",
+ "(type 1d)",
+ "BMP_STRING",
+ "HIGH_TAG_VALUE"
+};
+
+static const char * const flag_names[] = { /* flags, right to left */
+ "OPTIONAL",
+ "EXPLICIT",
+ "ANY",
+ "INLINE",
+ "POINTER",
+ "GROUP",
+ "DYNAMIC",
+ "SKIP",
+ "INNER",
+ "SAVE",
+ "", /* decoder ignores "MAY_STREAM", */
+ "SKIP_REST",
+ "CHOICE",
+ "NO_STREAM",
+ "DEBUG_BREAK",
+ "unknown 08",
+ "unknown 10",
+ "unknown 20",
+ "unknown 40",
+ "unknown 80"
+};
+
+static int /* bool */
+formatKind(unsigned long kind, char * buf)
+{
+ int i;
+ unsigned long k = kind & SEC_ASN1_TAGNUM_MASK;
+ unsigned long notag = kind & (SEC_ASN1_CHOICE | SEC_ASN1_POINTER |
+ SEC_ASN1_INLINE | SEC_ASN1_ANY | SEC_ASN1_SAVE);
+
+ buf[0] = 0;
+ if ((kind & SEC_ASN1_CLASS_MASK) != SEC_ASN1_UNIVERSAL) {
+ sprintf(buf, " %s", class_names[(kind & SEC_ASN1_CLASS_MASK) >> 6] );
+ buf += strlen(buf);
+ }
+ if (kind & SEC_ASN1_METHOD_MASK) {
+ sprintf(buf, " %s", method_names[1]);
+ buf += strlen(buf);
+ }
+ if ((kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL) {
+ if (k || !notag) {
+ sprintf(buf, " %s", type_names[k] );
+ if ((k == SEC_ASN1_SET || k == SEC_ASN1_SEQUENCE) &&
+ (kind & SEC_ASN1_GROUP)) {
+ buf += strlen(buf);
+ sprintf(buf, "_OF");
+ }
+ }
+ } else {
+ sprintf(buf, " [%d]", k);
+ }
+ buf += strlen(buf);
+
+ for (k = kind >> 8, i = 0; k; k >>= 1, ++i) {
+ if (k & 1) {
+ sprintf(buf, " %s", flag_names[i]);
+ buf += strlen(buf);
+ }
+ }
+ return notag != 0;
+}
+
+#endif /* DEBUG_ASN1D_STATES */
+
+typedef enum {
+ allDone,
+ decodeError,
+ keepGoing,
+ needBytes
+} sec_asn1d_parse_status;
+
+struct subitem {
+ const void *data;
+ unsigned long len; /* only used for substrings */
+ struct subitem *next;
+};
+
+typedef struct sec_asn1d_state_struct {
+ SEC_ASN1DecoderContext *top;
+ const SEC_ASN1Template *theTemplate;
+ void *dest;
+
+ void *our_mark; /* free on completion */
+
+ struct sec_asn1d_state_struct *parent; /* aka prev */
+ struct sec_asn1d_state_struct *child; /* aka next */
+
+ sec_asn1d_parse_place place;
+
+ /*
+ * XXX explain the next fields as clearly as possible...
+ */
+ unsigned char found_tag_modifiers;
+ unsigned char expect_tag_modifiers;
+ unsigned long check_tag_mask;
+ unsigned long found_tag_number;
+ unsigned long expect_tag_number;
+ unsigned long underlying_kind;
+
+ unsigned long contents_length;
+ unsigned long pending;
+ unsigned long consumed;
+
+ int depth;
+
+ /*
+ * Bit strings have their length adjusted -- the first octet of the
+ * contents contains a value between 0 and 7 which says how many bits
+ * at the end of the octets are not actually part of the bit string;
+ * when parsing bit strings we put that value here because we need it
+ * later, for adjustment of the length (when the whole string is done).
+ */
+ unsigned int bit_string_unused_bits;
+
+ /*
+ * The following are used for indefinite-length constructed strings.
+ */
+ struct subitem *subitems_head;
+ struct subitem *subitems_tail;
+
+ PRPackedBool
+ allocate, /* when true, need to allocate the destination */
+ endofcontents, /* this state ended up parsing end-of-contents octets */
+ explicit, /* we are handling an explicit header */
+ indefinite, /* the current item has indefinite-length encoding */
+ missing, /* an optional field that was not present */
+ optional, /* the template says this field may be omitted */
+ substring; /* this is a substring of a constructed string */
+
+} sec_asn1d_state;
+
+#define IS_HIGH_TAG_NUMBER(n) ((n) == SEC_ASN1_HIGH_TAG_NUMBER)
+#define LAST_TAG_NUMBER_BYTE(b) (((b) & 0x80) == 0)
+#define TAG_NUMBER_BITS 7
+#define TAG_NUMBER_MASK 0x7f
+
+#define LENGTH_IS_SHORT_FORM(b) (((b) & 0x80) == 0)
+#define LONG_FORM_LENGTH(b) ((b) & 0x7f)
+
+#define HIGH_BITS(field,cnt) ((field) >> ((sizeof(field) * 8) - (cnt)))
+
+
+/*
+ * An "outsider" will have an opaque pointer to this, created by calling
+ * SEC_ASN1DecoderStart(). It will be passed back in to all subsequent
+ * calls to SEC_ASN1DecoderUpdate(), and when done it is passed to
+ * SEC_ASN1DecoderFinish().
+ */
+struct sec_DecoderContext_struct {
+ PRArenaPool *our_pool; /* for our internal allocs */
+ PRArenaPool *their_pool; /* for destination structure allocs */
+#ifdef SEC_ASN1D_FREE_ON_ERROR /*
+ * XXX see comment below (by same
+ * ifdef) that explains why this
+ * does not work (need more smarts
+ * in order to free back to mark)
+ */
+ /*
+ * XXX how to make their_mark work in the case where they do NOT
+ * give us a pool pointer?
+ */
+ void *their_mark; /* free on error */
+#endif
+
+ sec_asn1d_state *current;
+ sec_asn1d_parse_status status;
+
+ SEC_ASN1NotifyProc notify_proc; /* call before/after handling field */
+ void *notify_arg; /* argument to notify_proc */
+ PRBool during_notify; /* true during call to notify_proc */
+
+ SEC_ASN1WriteProc filter_proc; /* pass field bytes to this */
+ void *filter_arg; /* argument to that function */
+ PRBool filter_only; /* do not allocate/store fields */
+};
+
+
+/*
+ * XXX this is a fairly generic function that may belong elsewhere
+ */
+static void *
+sec_asn1d_alloc (PRArenaPool *poolp, unsigned long len)
+{
+ void *thing;
+
+ if (poolp != NULL) {
+ /*
+ * Allocate from the pool.
+ */
+ thing = PORT_ArenaAlloc (poolp, len);
+ } else {
+ /*
+ * Allocate generically.
+ */
+ thing = PORT_Alloc (len);
+ }
+
+ return thing;
+}
+
+
+/*
+ * XXX this is a fairly generic function that may belong elsewhere
+ */
+static void *
+sec_asn1d_zalloc (PRArenaPool *poolp, unsigned long len)
+{
+ void *thing;
+
+ thing = sec_asn1d_alloc (poolp, len);
+ if (thing != NULL)
+ PORT_Memset (thing, 0, len);
+ return thing;
+}
+
+
+static sec_asn1d_state *
+sec_asn1d_push_state (SEC_ASN1DecoderContext *cx,
+ const SEC_ASN1Template *theTemplate,
+ void *dest, PRBool new_depth)
+{
+ sec_asn1d_state *state, *new_state;
+
+ state = cx->current;
+
+ PORT_Assert (state == NULL || state->child == NULL);
+
+ if (state != NULL) {
+ PORT_Assert (state->our_mark == NULL);
+ state->our_mark = PORT_ArenaMark (cx->our_pool);
+ }
+
+ new_state = (sec_asn1d_state*)sec_asn1d_zalloc (cx->our_pool,
+ sizeof(*new_state));
+ if (new_state == NULL) {
+ goto loser;
+ }
+
+ new_state->top = cx;
+ new_state->parent = state;
+ new_state->theTemplate = theTemplate;
+ new_state->place = notInUse;
+ if (dest != NULL)
+ new_state->dest = (char *)dest + theTemplate->offset;
+
+ if (state != NULL) {
+ new_state->depth = state->depth;
+ if (new_depth) {
+ if (++new_state->depth > SEC_ASN1D_MAX_DEPTH) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ goto loser;
+ }
+ }
+ state->child = new_state;
+ }
+
+ cx->current = new_state;
+ return new_state;
+
+loser:
+ cx->status = decodeError;
+ if (state != NULL) {
+ PORT_ArenaRelease(cx->our_pool, state->our_mark);
+ state->our_mark = NULL;
+ }
+ return NULL;
+}
+
+
+static void
+sec_asn1d_scrub_state (sec_asn1d_state *state)
+{
+ /*
+ * Some default "scrubbing".
+ * XXX right set of initializations?
+ */
+ state->place = beforeIdentifier;
+ state->endofcontents = PR_FALSE;
+ state->indefinite = PR_FALSE;
+ state->missing = PR_FALSE;
+ PORT_Assert (state->consumed == 0);
+}
+
+
+static void
+sec_asn1d_notify_before (SEC_ASN1DecoderContext *cx, void *dest, int depth)
+{
+ if (cx->notify_proc == NULL)
+ return;
+
+ cx->during_notify = PR_TRUE;
+ (* cx->notify_proc) (cx->notify_arg, PR_TRUE, dest, depth);
+ cx->during_notify = PR_FALSE;
+}
+
+
+static void
+sec_asn1d_notify_after (SEC_ASN1DecoderContext *cx, void *dest, int depth)
+{
+ if (cx->notify_proc == NULL)
+ return;
+
+ cx->during_notify = PR_TRUE;
+ (* cx->notify_proc) (cx->notify_arg, PR_FALSE, dest, depth);
+ cx->during_notify = PR_FALSE;
+}
+
+
+static sec_asn1d_state *
+sec_asn1d_init_state_based_on_template (sec_asn1d_state *state)
+{
+ PRBool explicit, optional, universal;
+ unsigned char expect_tag_modifiers;
+ unsigned long encode_kind, under_kind;
+ unsigned long check_tag_mask, expect_tag_number;
+
+
+ /* XXX Check that both of these tests are really needed/appropriate. */
+ if (state == NULL || state->top->status == decodeError)
+ return state;
+
+ encode_kind = state->theTemplate->kind;
+
+ if (encode_kind & SEC_ASN1_SAVE) {
+ /*
+ * This is a "magic" field that saves away all bytes, allowing
+ * the immediately following field to still be decoded from this
+ * same spot -- sort of a fork.
+ */
+ /* check that there are no extraneous bits */
+ PORT_Assert (encode_kind == SEC_ASN1_SAVE);
+ if (state->top->filter_only) {
+ /*
+ * If we are not storing, then we do not do the SAVE field
+ * at all. Just move ahead to the "real" field instead,
+ * doing the appropriate notify calls before and after.
+ */
+ sec_asn1d_notify_after (state->top, state->dest, state->depth);
+ /*
+ * Since we are not storing, allow for our current dest value
+ * to be NULL. (This might not actually occur, but right now I
+ * cannot convince myself one way or the other.) If it is NULL,
+ * assume that our parent dest can help us out.
+ */
+ if (state->dest == NULL)
+ state->dest = state->parent->dest;
+ else
+ state->dest = (char *)state->dest - state->theTemplate->offset;
+ state->theTemplate++;
+ if (state->dest != NULL)
+ state->dest = (char *)state->dest + state->theTemplate->offset;
+ sec_asn1d_notify_before (state->top, state->dest, state->depth);
+ encode_kind = state->theTemplate->kind;
+ PORT_Assert ((encode_kind & SEC_ASN1_SAVE) == 0);
+ } else {
+ sec_asn1d_scrub_state (state);
+ state->place = duringSaveEncoding;
+ state = sec_asn1d_push_state (state->top, SEC_AnyTemplate,
+ state->dest, PR_FALSE);
+ if (state != NULL)
+ state = sec_asn1d_init_state_based_on_template (state);
+ return state;
+ }
+ }
+
+
+ universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
+ ? PR_TRUE : PR_FALSE;
+
+ explicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_EXPLICIT;
+
+ optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_OPTIONAL;
+
+ PORT_Assert (!(explicit && universal)); /* bad templates */
+
+ encode_kind &= ~SEC_ASN1_DYNAMIC;
+ encode_kind &= ~SEC_ASN1_MAY_STREAM;
+
+ if (encode_kind & SEC_ASN1_CHOICE) {
+#if 0 /* XXX remove? */
+ sec_asn1d_state *child = sec_asn1d_push_state(state->top, state->theTemplate, state->dest, PR_FALSE);
+ if ((sec_asn1d_state *)NULL == child) {
+ return (sec_asn1d_state *)NULL;
+ }
+
+ child->allocate = state->allocate;
+ child->place = beforeChoice;
+ return child;
+#else
+ state->place = beforeChoice;
+ return state;
+#endif
+ }
+
+ if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || (!universal
+ && !explicit)) {
+ const SEC_ASN1Template *subt;
+ void *dest;
+ PRBool child_allocate;
+
+ PORT_Assert ((encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) == 0);
+
+ sec_asn1d_scrub_state (state);
+ child_allocate = PR_FALSE;
+
+ if (encode_kind & SEC_ASN1_POINTER) {
+ /*
+ * A POINTER means we need to allocate the destination for
+ * this field. But, since it may also be an optional field,
+ * we defer the allocation until later; we just record that
+ * it needs to be done.
+ *
+ * There are two possible scenarios here -- one is just a
+ * plain POINTER (kind of like INLINE, except with allocation)
+ * and the other is an implicitly-tagged POINTER. We don't
+ * need to do anything special here for the two cases, but
+ * since the template definition can be tricky, we do check
+ * that there are no extraneous bits set in encode_kind.
+ *
+ * XXX The same conditions which assert should set an error.
+ */
+ if (universal) {
+ /*
+ * "universal" means this entry is a standalone POINTER;
+ * there should be no other bits set in encode_kind.
+ */
+ PORT_Assert (encode_kind == SEC_ASN1_POINTER);
+ } else {
+ /*
+ * If we get here we have an implicitly-tagged field
+ * that needs to be put into a POINTER. The subtemplate
+ * will determine how to decode the field, but encode_kind
+ * describes the (implicit) tag we are looking for.
+ * The non-tag bits of encode_kind will be ignored by
+ * the code below; none of them should be set, however,
+ * except for the POINTER bit itself -- so check that.
+ */
+ PORT_Assert ((encode_kind & ~SEC_ASN1_TAG_MASK)
+ == SEC_ASN1_POINTER);
+ }
+ if (!state->top->filter_only)
+ child_allocate = PR_TRUE;
+ dest = NULL;
+ state->place = afterPointer;
+ } else {
+ dest = state->dest;
+ if (encode_kind & SEC_ASN1_INLINE) {
+ /* check that there are no extraneous bits */
+ PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional);
+ state->place = afterInline;
+ } else {
+ state->place = afterImplicit;
+ }
+ }
+
+ state->optional = optional;
+ subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->dest, PR_FALSE);
+ state = sec_asn1d_push_state (state->top, subt, dest, PR_FALSE);
+ if (state == NULL)
+ return NULL;
+
+ state->allocate = child_allocate;
+
+ if (universal) {
+ state = sec_asn1d_init_state_based_on_template (state);
+ if (state != NULL) {
+ /*
+ * If this field is optional, we need to record that on
+ * the pushed child so it won't fail if the field isn't
+ * found. I can't think of a way that this new state
+ * could already have optional set (which we would wipe
+ * out below if our local optional is not set) -- but
+ * just to be sure, assert that it isn't set.
+ */
+ PORT_Assert (!state->optional);
+ state->optional = optional;
+ }
+ return state;
+ }
+
+ under_kind = state->theTemplate->kind;
+ under_kind &= ~SEC_ASN1_MAY_STREAM;
+ } else if (explicit) {
+ /*
+ * For explicit, we only need to match the encoding tag next,
+ * then we will push another state to handle the entire inner
+ * part. In this case, there is no underlying kind which plays
+ * any part in the determination of the outer, explicit tag.
+ * So we just set under_kind to 0, which is not a valid tag,
+ * and the rest of the tag matching stuff should be okay.
+ */
+ under_kind = 0;
+ } else {
+ /*
+ * Nothing special; the underlying kind and the given encoding
+ * information are the same.
+ */
+ under_kind = encode_kind;
+ }
+
+ /* XXX is this the right set of bits to test here? */
+ PORT_Assert ((under_kind & (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL
+ | SEC_ASN1_MAY_STREAM
+ | SEC_ASN1_INLINE | SEC_ASN1_POINTER)) == 0);
+
+ if (encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) {
+ PORT_Assert (encode_kind == under_kind);
+ if (encode_kind & SEC_ASN1_SKIP) {
+ PORT_Assert (!optional);
+ PORT_Assert (encode_kind == SEC_ASN1_SKIP);
+ state->dest = NULL;
+ }
+ check_tag_mask = 0;
+ expect_tag_modifiers = 0;
+ expect_tag_number = 0;
+ } else {
+ check_tag_mask = SEC_ASN1_TAG_MASK;
+ expect_tag_modifiers = (unsigned char)encode_kind & SEC_ASN1_TAG_MASK
+ & ~SEC_ASN1_TAGNUM_MASK;
+ /*
+ * XXX This assumes only single-octet identifiers. To handle
+ * the HIGH TAG form we would need to do some more work, especially
+ * in how to specify them in the template, because right now we
+ * do not provide a way to specify more *tag* bits in encode_kind.
+ */
+ expect_tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK;
+
+ switch (under_kind & SEC_ASN1_TAGNUM_MASK) {
+ case SEC_ASN1_SET:
+ /*
+ * XXX A plain old SET (as opposed to a SET OF) is not implemented.
+ * If it ever is, remove this assert...
+ */
+ PORT_Assert ((under_kind & SEC_ASN1_GROUP) != 0);
+ /* fallthru */
+ case SEC_ASN1_SEQUENCE:
+ expect_tag_modifiers |= SEC_ASN1_CONSTRUCTED;
+ break;
+ case SEC_ASN1_BIT_STRING:
+ case SEC_ASN1_BMP_STRING:
+ case SEC_ASN1_GENERALIZED_TIME:
+ case SEC_ASN1_IA5_STRING:
+ case SEC_ASN1_OCTET_STRING:
+ case SEC_ASN1_PRINTABLE_STRING:
+ case SEC_ASN1_T61_STRING:
+ case SEC_ASN1_UNIVERSAL_STRING:
+ case SEC_ASN1_UTC_TIME:
+ case SEC_ASN1_UTF8_STRING:
+ case SEC_ASN1_VISIBLE_STRING:
+ check_tag_mask &= ~SEC_ASN1_CONSTRUCTED;
+ break;
+ }
+ }
+
+ state->check_tag_mask = check_tag_mask;
+ state->expect_tag_modifiers = expect_tag_modifiers;
+ state->expect_tag_number = expect_tag_number;
+ state->underlying_kind = under_kind;
+ state->explicit = explicit;
+ state->optional = optional;
+
+ sec_asn1d_scrub_state (state);
+
+ return state;
+}
+
+static sec_asn1d_state *
+sec_asn1d_get_enclosing_construct(sec_asn1d_state *state)
+{
+ for (state = state->parent; state; state = state->parent) {
+ sec_asn1d_parse_place place = state->place;
+ if (place != afterImplicit &&
+ place != afterPointer &&
+ place != afterInline &&
+ place != afterSaveEncoding &&
+ place != duringSaveEncoding &&
+ place != duringChoice) {
+
+ /* we've walked up the stack to a state that represents
+ ** the enclosing construct.
+ */
+ break;
+ }
+ }
+ return state;
+}
+
+static PRBool
+sec_asn1d_parent_allows_EOC(sec_asn1d_state *state)
+{
+ /* get state of enclosing construct. */
+ state = sec_asn1d_get_enclosing_construct(state);
+ if (state) {
+ sec_asn1d_parse_place place = state->place;
+ /* Is it one of the types that permits an unexpected EOC? */
+ int eoc_permitted =
+ (place == duringGroup ||
+ place == duringConstructedString ||
+ state->child->optional);
+ return (state->indefinite && eoc_permitted) ? PR_TRUE : PR_FALSE;
+ }
+ return PR_FALSE;
+}
+
+static unsigned long
+sec_asn1d_parse_identifier (sec_asn1d_state *state,
+ const char *buf, unsigned long len)
+{
+ unsigned char byte;
+ unsigned char tag_number;
+
+ PORT_Assert (state->place == beforeIdentifier);
+
+ if (len == 0) {
+ state->top->status = needBytes;
+ return 0;
+ }
+
+ byte = (unsigned char) *buf;
+#ifdef DEBUG_ASN1D_STATES
+ {
+ char kindBuf[256];
+ formatKind(byte, kindBuf);
+ printf("Found tag %02x %s\n", byte, kindBuf);
+ }
+#endif
+ tag_number = byte & SEC_ASN1_TAGNUM_MASK;
+
+ if (IS_HIGH_TAG_NUMBER (tag_number)) {
+ state->place = duringIdentifier;
+ state->found_tag_number = 0;
+ /*
+ * Actually, we have no idea how many bytes are pending, but we
+ * do know that it is at least 1. That is all we know; we have
+ * to look at each byte to know if there is another, etc.
+ */
+ state->pending = 1;
+ } else {
+ if (byte == 0 && sec_asn1d_parent_allows_EOC(state)) {
+ /*
+ * Our parent has indefinite-length encoding, and the
+ * entire tag found is 0, so it seems that we have hit the
+ * end-of-contents octets. To handle this, we just change
+ * our state to that which expects to get the bytes of the
+ * end-of-contents octets and let that code re-read this byte
+ * so that our categorization of field types is correct.
+ * After that, our parent will then deal with everything else.
+ */
+ state->place = duringEndOfContents;
+ state->pending = 2;
+ state->found_tag_number = 0;
+ state->found_tag_modifiers = 0;
+ /*
+ * We might be an optional field that is, as we now find out,
+ * missing. Give our parent a clue that this happened.
+ */
+ if (state->optional)
+ state->missing = PR_TRUE;
+ return 0;
+ }
+ state->place = afterIdentifier;
+ state->found_tag_number = tag_number;
+ }
+ state->found_tag_modifiers = byte & ~SEC_ASN1_TAGNUM_MASK;
+
+ return 1;
+}
+
+
+static unsigned long
+sec_asn1d_parse_more_identifier (sec_asn1d_state *state,
+ const char *buf, unsigned long len)
+{
+ unsigned char byte;
+ int count;
+
+ PORT_Assert (state->pending == 1);
+ PORT_Assert (state->place == duringIdentifier);
+
+ if (len == 0) {
+ state->top->status = needBytes;
+ return 0;
+ }
+
+ count = 0;
+
+ while (len && state->pending) {
+ if (HIGH_BITS (state->found_tag_number, TAG_NUMBER_BITS) != 0) {
+ /*
+ * The given high tag number overflows our container;
+ * just give up. This is not likely to *ever* happen.
+ */
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return 0;
+ }
+
+ state->found_tag_number <<= TAG_NUMBER_BITS;
+
+ byte = (unsigned char) buf[count++];
+ state->found_tag_number |= (byte & TAG_NUMBER_MASK);
+
+ len--;
+ if (LAST_TAG_NUMBER_BYTE (byte))
+ state->pending = 0;
+ }
+
+ if (state->pending == 0)
+ state->place = afterIdentifier;
+
+ return count;
+}
+
+
+static void
+sec_asn1d_confirm_identifier (sec_asn1d_state *state)
+{
+ PRBool match;
+
+ PORT_Assert (state->place == afterIdentifier);
+
+ match = (PRBool)(((state->found_tag_modifiers & state->check_tag_mask)
+ == state->expect_tag_modifiers)
+ && ((state->found_tag_number & state->check_tag_mask)
+ == state->expect_tag_number));
+ if (match) {
+ state->place = beforeLength;
+ } else {
+ if (state->optional) {
+ state->missing = PR_TRUE;
+ state->place = afterEndOfContents;
+ } else {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ }
+ }
+}
+
+
+static unsigned long
+sec_asn1d_parse_length (sec_asn1d_state *state,
+ const char *buf, unsigned long len)
+{
+ unsigned char byte;
+
+ PORT_Assert (state->place == beforeLength);
+
+ if (len == 0) {
+ state->top->status = needBytes;
+ return 0;
+ }
+
+ /*
+ * The default/likely outcome. It may get adjusted below.
+ */
+ state->place = afterLength;
+
+ byte = (unsigned char) *buf;
+
+ if (LENGTH_IS_SHORT_FORM (byte)) {
+ state->contents_length = byte;
+ } else {
+ state->contents_length = 0;
+ state->pending = LONG_FORM_LENGTH (byte);
+ if (state->pending == 0) {
+ state->indefinite = PR_TRUE;
+ } else {
+ state->place = duringLength;
+ }
+ }
+
+ /* If we're parsing an ANY, SKIP, or SAVE template, and
+ ** the object being saved is definite length encoded and constructed,
+ ** there's no point in decoding that construct's members.
+ ** So, just forget it's constructed and treat it as primitive.
+ ** (SAVE appears as an ANY at this point)
+ */
+ if (!state->indefinite &&
+ (state->underlying_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP))) {
+ state->found_tag_modifiers &= ~SEC_ASN1_CONSTRUCTED;
+ }
+
+ return 1;
+}
+
+
+static unsigned long
+sec_asn1d_parse_more_length (sec_asn1d_state *state,
+ const char *buf, unsigned long len)
+{
+ int count;
+
+ PORT_Assert (state->pending > 0);
+ PORT_Assert (state->place == duringLength);
+
+ if (len == 0) {
+ state->top->status = needBytes;
+ return 0;
+ }
+
+ count = 0;
+
+ while (len && state->pending) {
+ if (HIGH_BITS (state->contents_length, 9) != 0) {
+ /*
+ * The given full content length overflows our container;
+ * just give up.
+ */
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return 0;
+ }
+
+ state->contents_length <<= 8;
+ state->contents_length |= (unsigned char) buf[count++];
+
+ len--;
+ state->pending--;
+ }
+
+ if (state->pending == 0)
+ state->place = afterLength;
+
+ return count;
+}
+
+
+static void
+sec_asn1d_prepare_for_contents (sec_asn1d_state *state)
+{
+ SECItem *item;
+ PRArenaPool *poolp;
+ unsigned long alloc_len;
+
+#ifdef DEBUG_ASN1D_STATES
+ {
+ printf("Found Length %d %s\n", state->contents_length,
+ state->indefinite ? "indefinite" : "");
+ }
+#endif
+
+ /*
+ * XXX I cannot decide if this allocation should exclude the case
+ * where state->endofcontents is true -- figure it out!
+ */
+ if (state->allocate) {
+ void *dest;
+
+ PORT_Assert (state->dest == NULL);
+ /*
+ * We are handling a POINTER or a member of a GROUP, and need to
+ * allocate for the data structure.
+ */
+ dest = sec_asn1d_zalloc (state->top->their_pool,
+ state->theTemplate->size);
+ if (dest == NULL) {
+ state->top->status = decodeError;
+ return;
+ }
+ state->dest = (char *)dest + state->theTemplate->offset;
+
+ /*
+ * For a member of a GROUP, our parent will later put the
+ * pointer wherever it belongs. But for a POINTER, we need
+ * to record the destination now, in case notify or filter
+ * procs need access to it -- they cannot find it otherwise,
+ * until it is too late (for one-pass processing).
+ */
+ if (state->parent->place == afterPointer) {
+ void **placep;
+
+ placep = state->parent->dest;
+ *placep = dest;
+ }
+ }
+
+ /*
+ * Remember, length may be indefinite here! In that case,
+ * both contents_length and pending will be zero.
+ */
+ state->pending = state->contents_length;
+
+ /* If this item has definite length encoding, and
+ ** is enclosed by a definite length constructed type,
+ ** make sure it isn't longer than the remaining space in that
+ ** constructed type.
+ */
+ if (state->contents_length > 0) {
+ sec_asn1d_state *parent = sec_asn1d_get_enclosing_construct(state);
+ if (parent && !parent->indefinite &&
+ state->consumed + state->contents_length > parent->pending) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return;
+ }
+ }
+
+ /*
+ * An EXPLICIT is nothing but an outer header, which we have
+ * already parsed and accepted. Now we need to do the inner
+ * header and its contents.
+ */
+ if (state->explicit) {
+ state->place = afterExplicit;
+ state = sec_asn1d_push_state (state->top,
+ SEC_ASN1GetSubtemplate(state->theTemplate,
+ state->dest,
+ PR_FALSE),
+ state->dest, PR_TRUE);
+ if (state != NULL)
+ state = sec_asn1d_init_state_based_on_template (state);
+ return;
+ }
+
+ /*
+ * For GROUP (SET OF, SEQUENCE OF), even if we know the length here
+ * we cannot tell how many items we will end up with ... so push a
+ * state that can keep track of "children" (the individual members
+ * of the group; we will allocate as we go and put them all together
+ * at the end.
+ */
+ if (state->underlying_kind & SEC_ASN1_GROUP) {
+ /* XXX If this assertion holds (should be able to confirm it via
+ * inspection, too) then move this code into the switch statement
+ * below under cases SET_OF and SEQUENCE_OF; it will be cleaner.
+ */
+ PORT_Assert (state->underlying_kind == SEC_ASN1_SET_OF
+ || state->underlying_kind == SEC_ASN1_SEQUENCE_OF
+ || state->underlying_kind == (SEC_ASN1_SEQUENCE_OF|SEC_ASN1_DYNAMIC)
+ || state->underlying_kind == (SEC_ASN1_SEQUENCE_OF|SEC_ASN1_DYNAMIC)
+ );
+ if (state->contents_length != 0 || state->indefinite) {
+ const SEC_ASN1Template *subt;
+
+ state->place = duringGroup;
+ subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->dest,
+ PR_FALSE);
+ state = sec_asn1d_push_state (state->top, subt, NULL, PR_TRUE);
+ if (state != NULL) {
+ if (!state->top->filter_only)
+ state->allocate = PR_TRUE; /* XXX propogate this? */
+ /*
+ * Do the "before" field notification for next in group.
+ */
+ sec_asn1d_notify_before (state->top, state->dest, state->depth);
+ state = sec_asn1d_init_state_based_on_template (state);
+ }
+ } else {
+ /*
+ * A group of zero; we are done.
+ * Set state to afterGroup and let that code plant the NULL.
+ */
+ state->place = afterGroup;
+ }
+ return;
+ }
+
+ switch (state->underlying_kind) {
+ case SEC_ASN1_SEQUENCE:
+ /*
+ * We need to push a child to handle the individual fields.
+ */
+ state->place = duringSequence;
+ state = sec_asn1d_push_state (state->top, state->theTemplate + 1,
+ state->dest, PR_TRUE);
+ if (state != NULL) {
+ /*
+ * Do the "before" field notification.
+ */
+ sec_asn1d_notify_before (state->top, state->dest, state->depth);
+ state = sec_asn1d_init_state_based_on_template (state);
+ }
+ break;
+
+ case SEC_ASN1_SET: /* XXX SET is not really implemented */
+ /*
+ * XXX A plain SET requires special handling; scanning of a
+ * template to see where a field should go (because by definition,
+ * they are not in any particular order, and you have to look at
+ * each tag to disambiguate what the field is). We may never
+ * implement this because in practice, it seems to be unused.
+ */
+ PORT_Assert(0);
+ PORT_SetError (SEC_ERROR_BAD_DER); /* XXX */
+ state->top->status = decodeError;
+ break;
+
+ case SEC_ASN1_NULL:
+ /*
+ * The NULL type, by definition, is "nothing", content length of zero.
+ * An indefinite-length encoding is not alloweed.
+ */
+ if (state->contents_length || state->indefinite) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ break;
+ }
+ if (state->dest != NULL) {
+ item = (SECItem *)(state->dest);
+ item->data = NULL;
+ item->len = 0;
+ }
+ state->place = afterEndOfContents;
+ break;
+
+ case SEC_ASN1_BMP_STRING:
+ /* Error if length is not divisable by 2 */
+ if (state->contents_length % 2) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ break;
+ }
+ /* otherwise, handle as other string types */
+ goto regular_string_type;
+
+ case SEC_ASN1_UNIVERSAL_STRING:
+ /* Error if length is not divisable by 4 */
+ if (state->contents_length % 4) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ break;
+ }
+ /* otherwise, handle as other string types */
+ goto regular_string_type;
+
+ case SEC_ASN1_SKIP:
+ case SEC_ASN1_ANY:
+ case SEC_ASN1_ANY_CONTENTS:
+ /*
+ * These are not (necessarily) strings, but they need nearly
+ * identical handling (especially when we need to deal with
+ * constructed sub-pieces), so we pretend they are.
+ */
+ /* fallthru */
+regular_string_type:
+ case SEC_ASN1_BIT_STRING:
+ case SEC_ASN1_IA5_STRING:
+ case SEC_ASN1_OCTET_STRING:
+ case SEC_ASN1_PRINTABLE_STRING:
+ case SEC_ASN1_T61_STRING:
+ case SEC_ASN1_UTC_TIME:
+ case SEC_ASN1_UTF8_STRING:
+ case SEC_ASN1_VISIBLE_STRING:
+ /*
+ * We are allocating for a primitive or a constructed string.
+ * If it is a constructed string, it may also be indefinite-length.
+ * If it is primitive, the length can (legally) be zero.
+ * Our first order of business is to allocate the memory for
+ * the string, if we can (if we know the length).
+ */
+ item = (SECItem *)(state->dest);
+
+ /*
+ * If the item is a definite-length constructed string, then
+ * the contents_length is actually larger than what we need
+ * (because it also counts each intermediate header which we
+ * will be throwing away as we go), but it is a perfectly good
+ * upper bound that we just allocate anyway, and then concat
+ * as we go; we end up wasting a few extra bytes but save a
+ * whole other copy.
+ */
+ alloc_len = state->contents_length;
+ poolp = NULL; /* quiet compiler warnings about unused... */
+
+ if (item == NULL || state->top->filter_only) {
+ if (item != NULL) {
+ item->data = NULL;
+ item->len = 0;
+ }
+ alloc_len = 0;
+ } else if (state->substring) {
+ /*
+ * If we are a substring of a constructed string, then we may
+ * not have to allocate anything (because our parent, the
+ * actual constructed string, did it for us). If we are a
+ * substring and we *do* have to allocate, that means our
+ * parent is an indefinite-length, so we allocate from our pool;
+ * later our parent will copy our string into the aggregated
+ * whole and free our pool allocation.
+ */
+ if (item->data == NULL) {
+ PORT_Assert (item->len == 0);
+ poolp = state->top->our_pool;
+ } else {
+ alloc_len = 0;
+ }
+ } else {
+ item->len = 0;
+ item->data = NULL;
+ poolp = state->top->their_pool;
+ }
+
+ if (alloc_len || ((! state->indefinite)
+ && (state->subitems_head != NULL))) {
+ struct subitem *subitem;
+ int len;
+
+ PORT_Assert (item);
+ if (!item) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return;
+ }
+ PORT_Assert (item->len == 0 && item->data == NULL);
+ /*
+ * Check for and handle an ANY which has stashed aside the
+ * header (identifier and length) bytes for us to include
+ * in the saved contents.
+ */
+ if (state->subitems_head != NULL) {
+ PORT_Assert (state->underlying_kind == SEC_ASN1_ANY);
+ for (subitem = state->subitems_head;
+ subitem != NULL; subitem = subitem->next)
+ alloc_len += subitem->len;
+ }
+
+ item->data = (unsigned char*)sec_asn1d_zalloc (poolp, alloc_len);
+ if (item->data == NULL) {
+ state->top->status = decodeError;
+ break;
+ }
+
+ len = 0;
+ for (subitem = state->subitems_head;
+ subitem != NULL; subitem = subitem->next) {
+ PORT_Memcpy (item->data + len, subitem->data, subitem->len);
+ len += subitem->len;
+ }
+ item->len = len;
+
+ /*
+ * Because we use arenas and have a mark set, we later free
+ * everything we have allocated, so this does *not* present
+ * a memory leak (it is just temporarily left dangling).
+ */
+ state->subitems_head = state->subitems_tail = NULL;
+ }
+
+ if (state->contents_length == 0 && (! state->indefinite)) {
+ /*
+ * A zero-length simple or constructed string; we are done.
+ */
+ state->place = afterEndOfContents;
+ } else if (state->found_tag_modifiers & SEC_ASN1_CONSTRUCTED) {
+ const SEC_ASN1Template *sub;
+
+ switch (state->underlying_kind) {
+ case SEC_ASN1_ANY:
+ case SEC_ASN1_ANY_CONTENTS:
+ sub = SEC_AnyTemplate;
+ break;
+ case SEC_ASN1_BIT_STRING:
+ sub = SEC_BitStringTemplate;
+ break;
+ case SEC_ASN1_BMP_STRING:
+ sub = SEC_BMPStringTemplate;
+ break;
+ case SEC_ASN1_GENERALIZED_TIME:
+ sub = SEC_GeneralizedTimeTemplate;
+ break;
+ case SEC_ASN1_IA5_STRING:
+ sub = SEC_IA5StringTemplate;
+ break;
+ case SEC_ASN1_OCTET_STRING:
+ sub = SEC_OctetStringTemplate;
+ break;
+ case SEC_ASN1_PRINTABLE_STRING:
+ sub = SEC_PrintableStringTemplate;
+ break;
+ case SEC_ASN1_T61_STRING:
+ sub = SEC_T61StringTemplate;
+ break;
+ case SEC_ASN1_UNIVERSAL_STRING:
+ sub = SEC_UniversalStringTemplate;
+ break;
+ case SEC_ASN1_UTC_TIME:
+ sub = SEC_UTCTimeTemplate;
+ break;
+ case SEC_ASN1_UTF8_STRING:
+ sub = SEC_UTF8StringTemplate;
+ break;
+ case SEC_ASN1_VISIBLE_STRING:
+ sub = SEC_VisibleStringTemplate;
+ break;
+ case SEC_ASN1_SKIP:
+ sub = SEC_SkipTemplate;
+ break;
+ default: /* redundant given outer switch cases, but */
+ PORT_Assert(0); /* the compiler does not seem to know that, */
+ sub = NULL; /* so just do enough to quiet it. */
+ break;
+ }
+
+ state->place = duringConstructedString;
+ state = sec_asn1d_push_state (state->top, sub, item, PR_TRUE);
+ if (state != NULL) {
+ state->substring = PR_TRUE; /* XXX propogate? */
+ state = sec_asn1d_init_state_based_on_template (state);
+ }
+ } else if (state->indefinite) {
+ /*
+ * An indefinite-length string *must* be constructed!
+ */
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ } else {
+ /*
+ * A non-zero-length simple string.
+ */
+ if (state->underlying_kind == SEC_ASN1_BIT_STRING)
+ state->place = beforeBitString;
+ else
+ state->place = duringLeaf;
+ }
+ break;
+
+ default:
+ /*
+ * We are allocating for a simple leaf item.
+ */
+ if (state->contents_length) {
+ if (state->dest != NULL) {
+ item = (SECItem *)(state->dest);
+ item->len = 0;
+ if (state->top->filter_only) {
+ item->data = NULL;
+ } else {
+ item->data = (unsigned char*)
+ sec_asn1d_zalloc (state->top->their_pool,
+ state->contents_length);
+ if (item->data == NULL) {
+ state->top->status = decodeError;
+ return;
+ }
+ }
+ }
+ state->place = duringLeaf;
+ } else {
+ /*
+ * An indefinite-length or zero-length item is not allowed.
+ * (All legal cases of such were handled above.)
+ */
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ }
+ }
+}
+
+
+static void
+sec_asn1d_free_child (sec_asn1d_state *state, PRBool error)
+{
+ if (state->child != NULL) {
+ PORT_Assert (error || state->child->consumed == 0);
+ PORT_Assert (state->our_mark != NULL);
+ PORT_ArenaZRelease (state->top->our_pool, state->our_mark);
+ if (error && state->top->their_pool == NULL) {
+ /*
+ * XXX We need to free anything allocated.
+ * At this point, we failed in the middle of decoding. But we
+ * can't free the data we previously allocated with PR_Malloc
+ * unless we keep track of every pointer. So instead we have a
+ * memory leak when decoding fails half-way, unless an arena is
+ * used. See bug 95311 .
+ */
+ }
+ state->child = NULL;
+ state->our_mark = NULL;
+ } else {
+ /*
+ * It is important that we do not leave a mark unreleased/unmarked.
+ * But I do not think we should ever have one set in this case, only
+ * if we had a child (handled above). So check for that. If this
+ * assertion should ever get hit, then we probably need to add code
+ * here to release back to our_mark (and then set our_mark to NULL).
+ */
+ PORT_Assert (state->our_mark == NULL);
+ }
+ state->place = beforeEndOfContents;
+}
+
+/* We have just saved an entire encoded ASN.1 object (type) for a SAVE
+** template, and now in the next template, we are going to decode that
+** saved data by calling SEC_ASN1DecoderUpdate recursively.
+** If that recursive call fails with needBytes, it is a fatal error,
+** because the encoded object should have been complete.
+** If that recursive call fails with decodeError, it will have already
+** cleaned up the state stack, so we must bail out quickly.
+**
+** These checks of the status returned by the recursive call are now
+** done in the caller of this function, immediately after it returns.
+*/
+static void
+sec_asn1d_reuse_encoding (sec_asn1d_state *state)
+{
+ sec_asn1d_state *child;
+ unsigned long consumed;
+ SECItem *item;
+ void *dest;
+
+
+ child = state->child;
+ PORT_Assert (child != NULL);
+
+ consumed = child->consumed;
+ child->consumed = 0;
+
+ item = (SECItem *)(state->dest);
+ PORT_Assert (item != NULL);
+
+ PORT_Assert (item->len == consumed);
+
+ /*
+ * Free any grandchild.
+ */
+ sec_asn1d_free_child (child, PR_FALSE);
+
+ /*
+ * Notify after the SAVE field.
+ */
+ sec_asn1d_notify_after (state->top, state->dest, state->depth);
+
+ /*
+ * Adjust to get new dest and move forward.
+ */
+ dest = (char *)state->dest - state->theTemplate->offset;
+ state->theTemplate++;
+ child->dest = (char *)dest + state->theTemplate->offset;
+ child->theTemplate = state->theTemplate;
+
+ /*
+ * Notify before the "real" field.
+ */
+ PORT_Assert (state->depth == child->depth);
+ sec_asn1d_notify_before (state->top, child->dest, child->depth);
+
+ /*
+ * This will tell DecoderUpdate to return when it is done.
+ */
+ state->place = afterSaveEncoding;
+
+ /*
+ * We already have a child; "push" it by making it current.
+ */
+ state->top->current = child;
+
+ /*
+ * And initialize it so it is ready to parse.
+ */
+ (void) sec_asn1d_init_state_based_on_template(child);
+
+ /*
+ * Now parse that out of our data.
+ */
+ if (SEC_ASN1DecoderUpdate (state->top,
+ (char *) item->data, item->len) != SECSuccess)
+ return;
+ if (state->top->status == needBytes) {
+ return;
+ }
+
+ PORT_Assert (state->top->current == state);
+ PORT_Assert (state->child == child);
+
+ /*
+ * That should have consumed what we consumed before.
+ */
+ PORT_Assert (consumed == child->consumed);
+ child->consumed = 0;
+
+ /*
+ * Done.
+ */
+ state->consumed += consumed;
+ child->place = notInUse;
+ state->place = afterEndOfContents;
+}
+
+
+static unsigned long
+sec_asn1d_parse_leaf (sec_asn1d_state *state,
+ const char *buf, unsigned long len)
+{
+ SECItem *item;
+ unsigned long bufLen;
+
+ if (len == 0) {
+ state->top->status = needBytes;
+ return 0;
+ }
+
+ if (state->pending < len)
+ len = state->pending;
+
+ bufLen = len;
+
+ item = (SECItem *)(state->dest);
+ if (item != NULL && item->data != NULL) {
+ /* Strip leading zeroes when target is unsigned integer */
+ if (state->underlying_kind == SEC_ASN1_INTEGER && /* INTEGER */
+ item->len == 0 && /* MSB */
+ item->type == siUnsignedInteger) /* unsigned */
+ {
+ while (len > 1 && buf[0] == 0) { /* leading 0 */
+ buf++;
+ len--;
+ }
+ }
+ PORT_Memcpy (item->data + item->len, buf, len);
+ item->len += len;
+ }
+ state->pending -= bufLen;
+ if (state->pending == 0)
+ state->place = beforeEndOfContents;
+
+ return bufLen;
+}
+
+
+static unsigned long
+sec_asn1d_parse_bit_string (sec_asn1d_state *state,
+ const char *buf, unsigned long len)
+{
+ unsigned char byte;
+
+ /*PORT_Assert (state->pending > 0); */
+ PORT_Assert (state->place == beforeBitString);
+
+ if (state->pending == 0) {
+ if (state->dest != NULL) {
+ SECItem *item = (SECItem *)(state->dest);
+ item->data = NULL;
+ item->len = 0;
+ state->place = beforeEndOfContents;
+ return 0;
+ }
+ }
+
+ if (len == 0) {
+ state->top->status = needBytes;
+ return 0;
+ }
+
+ byte = (unsigned char) *buf;
+ if (byte > 7) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return 0;
+ }
+
+ state->bit_string_unused_bits = byte;
+ state->place = duringBitString;
+ state->pending -= 1;
+
+ return 1;
+}
+
+
+static unsigned long
+sec_asn1d_parse_more_bit_string (sec_asn1d_state *state,
+ const char *buf, unsigned long len)
+{
+ PORT_Assert (state->place == duringBitString);
+ if (state->pending == 0) {
+ /* An empty bit string with some unused bits is invalid. */
+ if (state->bit_string_unused_bits) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ } else {
+ /* An empty bit string with no unused bits is OK. */
+ state->place = beforeEndOfContents;
+ }
+ return 0;
+ }
+
+ len = sec_asn1d_parse_leaf (state, buf, len);
+ if (state->place == beforeEndOfContents && state->dest != NULL) {
+ SECItem *item;
+
+ item = (SECItem *)(state->dest);
+ if (item->len)
+ item->len = (item->len << 3) - state->bit_string_unused_bits;
+ }
+
+ return len;
+}
+
+
+/*
+ * XXX All callers should be looking at return value to detect
+ * out-of-memory errors (and stop!).
+ */
+static struct subitem *
+sec_asn1d_add_to_subitems (sec_asn1d_state *state,
+ const void *data, unsigned long len,
+ PRBool copy_data)
+{
+ struct subitem *thing;
+
+ thing = (struct subitem*)sec_asn1d_zalloc (state->top->our_pool,
+ sizeof (struct subitem));
+ if (thing == NULL) {
+ state->top->status = decodeError;
+ return NULL;
+ }
+
+ if (copy_data) {
+ void *copy;
+ copy = sec_asn1d_alloc (state->top->our_pool, len);
+ if (copy == NULL) {
+ state->top->status = decodeError;
+ if (!state->top->our_pool)
+ PORT_Free(thing);
+ return NULL;
+ }
+ PORT_Memcpy (copy, data, len);
+ thing->data = copy;
+ } else {
+ thing->data = data;
+ }
+ thing->len = len;
+ thing->next = NULL;
+
+ if (state->subitems_head == NULL) {
+ PORT_Assert (state->subitems_tail == NULL);
+ state->subitems_head = state->subitems_tail = thing;
+ } else {
+ state->subitems_tail->next = thing;
+ state->subitems_tail = thing;
+ }
+
+ return thing;
+}
+
+
+static void
+sec_asn1d_record_any_header (sec_asn1d_state *state,
+ const char *buf,
+ unsigned long len)
+{
+ SECItem *item;
+
+ item = (SECItem *)(state->dest);
+ if (item != NULL && item->data != NULL) {
+ PORT_Assert (state->substring);
+ PORT_Memcpy (item->data + item->len, buf, len);
+ item->len += len;
+ } else {
+ sec_asn1d_add_to_subitems (state, buf, len, PR_TRUE);
+ }
+}
+
+
+/*
+ * We are moving along through the substrings of a constructed string,
+ * and have just finished parsing one -- we need to save our child data
+ * (if the child was not already writing directly into the destination)
+ * and then move forward by one.
+ *
+ * We also have to detect when we are done:
+ * - a definite-length encoding stops when our pending value hits 0
+ * - an indefinite-length encoding stops when our child is empty
+ * (which means it was the end-of-contents octets)
+ */
+static void
+sec_asn1d_next_substring (sec_asn1d_state *state)
+{
+ sec_asn1d_state *child;
+ SECItem *item;
+ unsigned long child_consumed;
+ PRBool done;
+
+ PORT_Assert (state->place == duringConstructedString);
+ PORT_Assert (state->child != NULL);
+
+ child = state->child;
+
+ child_consumed = child->consumed;
+ child->consumed = 0;
+ state->consumed += child_consumed;
+
+ done = PR_FALSE;
+
+ if (state->pending) {
+ PORT_Assert (!state->indefinite);
+ if (child_consumed > state->pending) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return;
+ }
+
+ state->pending -= child_consumed;
+ if (state->pending == 0)
+ done = PR_TRUE;
+ } else {
+ PORT_Assert (state->indefinite);
+
+ item = (SECItem *)(child->dest);
+ if (item != NULL && item->data != NULL) {
+ /*
+ * Save the string away for later concatenation.
+ */
+ PORT_Assert (item->data != NULL);
+ sec_asn1d_add_to_subitems (state, item->data, item->len, PR_FALSE);
+ /*
+ * Clear the child item for the next round.
+ */
+ item->data = NULL;
+ item->len = 0;
+ }
+
+ /*
+ * If our child was just our end-of-contents octets, we are done.
+ */
+ if (child->endofcontents)
+ done = PR_TRUE;
+ }
+
+ /*
+ * Stop or do the next one.
+ */
+ if (done) {
+ child->place = notInUse;
+ state->place = afterConstructedString;
+ } else {
+ sec_asn1d_scrub_state (child);
+ state->top->current = child;
+ }
+}
+
+
+/*
+ * We are doing a SET OF or SEQUENCE OF, and have just finished an item.
+ */
+static void
+sec_asn1d_next_in_group (sec_asn1d_state *state)
+{
+ sec_asn1d_state *child;
+ unsigned long child_consumed;
+
+ PORT_Assert (state->place == duringGroup);
+ PORT_Assert (state->child != NULL);
+
+ child = state->child;
+
+ child_consumed = child->consumed;
+ child->consumed = 0;
+ state->consumed += child_consumed;
+
+ /*
+ * If our child was just our end-of-contents octets, we are done.
+ */
+ if (child->endofcontents) {
+ /* XXX I removed the PORT_Assert (child->dest == NULL) because there
+ * was a bug in that a template that was a sequence of which also had
+ * a child of a sequence of, in an indefinite group was not working
+ * properly. This fix seems to work, (added the if statement below),
+ * and nothing appears broken, but I am putting this note here just
+ * in case. */
+ /*
+ * XXX No matter how many times I read that comment,
+ * I cannot figure out what case he was fixing. I believe what he
+ * did was deliberate, so I am loathe to touch it. I need to
+ * understand how it could ever be that child->dest != NULL but
+ * child->endofcontents is true, and why it is important to check
+ * that state->subitems_head is NULL. This really needs to be
+ * figured out, as I am not sure if the following code should be
+ * compensating for "offset", as is done a little farther below
+ * in the more normal case.
+ */
+ PORT_Assert (state->indefinite);
+ PORT_Assert (state->pending == 0);
+ if(child->dest && !state->subitems_head) {
+ sec_asn1d_add_to_subitems (state, child->dest, 0, PR_FALSE);
+ child->dest = NULL;
+ }
+
+ child->place = notInUse;
+ state->place = afterGroup;
+ return;
+ }
+
+ /*
+ * Do the "after" field notification for next in group.
+ */
+ sec_asn1d_notify_after (state->top, child->dest, child->depth);
+
+ /*
+ * Save it away (unless we are not storing).
+ */
+ if (child->dest != NULL) {
+ void *dest;
+
+ dest = child->dest;
+ dest = (char *)dest - child->theTemplate->offset;
+ sec_asn1d_add_to_subitems (state, dest, 0, PR_FALSE);
+ child->dest = NULL;
+ }
+
+ /*
+ * Account for those bytes; see if we are done.
+ */
+ if (state->pending) {
+ PORT_Assert (!state->indefinite);
+ if (child_consumed > state->pending) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return;
+ }
+
+ state->pending -= child_consumed;
+ if (state->pending == 0) {
+ child->place = notInUse;
+ state->place = afterGroup;
+ return;
+ }
+ }
+
+ /*
+ * Do the "before" field notification for next item in group.
+ */
+ sec_asn1d_notify_before (state->top, child->dest, child->depth);
+
+ /*
+ * Now we do the next one.
+ */
+ sec_asn1d_scrub_state (child);
+
+ /* Initialize child state from the template */
+ sec_asn1d_init_state_based_on_template(child);
+
+ state->top->current = child;
+}
+
+
+/*
+ * We are moving along through a sequence; move forward by one,
+ * (detecting end-of-sequence when it happens).
+ * XXX The handling of "missing" is ugly. Fix it.
+ */
+static void
+sec_asn1d_next_in_sequence (sec_asn1d_state *state)
+{
+ sec_asn1d_state *child;
+ unsigned long child_consumed;
+ PRBool child_missing;
+
+ PORT_Assert (state->place == duringSequence);
+ PORT_Assert (state->child != NULL);
+
+ child = state->child;
+
+ /*
+ * Do the "after" field notification.
+ */
+ sec_asn1d_notify_after (state->top, child->dest, child->depth);
+
+ child_missing = (PRBool) child->missing;
+ child_consumed = child->consumed;
+ child->consumed = 0;
+
+ /*
+ * Take care of accounting.
+ */
+ if (child_missing) {
+ PORT_Assert (child->optional);
+ } else {
+ state->consumed += child_consumed;
+ /*
+ * Free any grandchild.
+ */
+ sec_asn1d_free_child (child, PR_FALSE);
+ if (state->pending) {
+ PORT_Assert (!state->indefinite);
+ if (child_consumed > state->pending) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return;
+ }
+ state->pending -= child_consumed;
+ if (state->pending == 0) {
+ child->theTemplate++;
+ while (child->theTemplate->kind != 0) {
+ if ((child->theTemplate->kind & SEC_ASN1_OPTIONAL) == 0) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return;
+ }
+ child->theTemplate++;
+ }
+ child->place = notInUse;
+ state->place = afterEndOfContents;
+ return;
+ }
+ }
+ }
+
+ /*
+ * Move forward.
+ */
+ child->theTemplate++;
+ if (child->theTemplate->kind == 0) {
+ /*
+ * We are done with this sequence.
+ */
+ child->place = notInUse;
+ if (state->pending) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ } else if (child_missing) {
+ /*
+ * We got to the end, but have a child that started parsing
+ * and ended up "missing". The only legitimate reason for
+ * this is that we had one or more optional fields at the
+ * end of our sequence, and we were encoded indefinite-length,
+ * so when we went looking for those optional fields we
+ * found our end-of-contents octets instead.
+ * (Yes, this is ugly; dunno a better way to handle it.)
+ * So, first confirm the situation, and then mark that we
+ * are done.
+ */
+ if (state->indefinite && child->endofcontents) {
+ PORT_Assert (child_consumed == 2);
+ if (child_consumed != 2) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ } else {
+ state->consumed += child_consumed;
+ state->place = afterEndOfContents;
+ }
+ } else {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ }
+ } else {
+ /*
+ * We have to finish out, maybe reading end-of-contents octets;
+ * let the normal logic do the right thing.
+ */
+ state->place = beforeEndOfContents;
+ }
+ } else {
+ unsigned char child_found_tag_modifiers = 0;
+ unsigned long child_found_tag_number = 0;
+
+ /*
+ * Reset state and push.
+ */
+ if (state->dest != NULL)
+ child->dest = (char *)state->dest + child->theTemplate->offset;
+
+ /*
+ * Do the "before" field notification.
+ */
+ sec_asn1d_notify_before (state->top, child->dest, child->depth);
+
+ if (child_missing) { /* if previous child was missing, copy the tag data we already have */
+ child_found_tag_modifiers = child->found_tag_modifiers;
+ child_found_tag_number = child->found_tag_number;
+ }
+ state->top->current = child;
+ child = sec_asn1d_init_state_based_on_template (child);
+ if (child_missing && child) {
+ child->place = afterIdentifier;
+ child->found_tag_modifiers = child_found_tag_modifiers;
+ child->found_tag_number = child_found_tag_number;
+ child->consumed = child_consumed;
+ if (child->underlying_kind == SEC_ASN1_ANY
+ && !child->top->filter_only) {
+ /*
+ * If the new field is an ANY, and we are storing, then
+ * we need to save the tag out. We would have done this
+ * already in the normal case, but since we were looking
+ * for an optional field, and we did not find it, we only
+ * now realize we need to save the tag.
+ */
+ unsigned char identifier;
+
+ /*
+ * Check that we did not end up with a high tag; for that
+ * we need to re-encode the tag into multiple bytes in order
+ * to store it back to look like what we parsed originally.
+ * In practice this does not happen, but for completeness
+ * sake it should probably be made to work at some point.
+ */
+ PORT_Assert (child_found_tag_number < SEC_ASN1_HIGH_TAG_NUMBER);
+ identifier = (unsigned char)(child_found_tag_modifiers | child_found_tag_number);
+ sec_asn1d_record_any_header (child, (char *) &identifier, 1);
+ }
+ }
+ }
+}
+
+
+static void
+sec_asn1d_concat_substrings (sec_asn1d_state *state)
+{
+ PORT_Assert (state->place == afterConstructedString);
+
+ if (state->subitems_head != NULL) {
+ struct subitem *substring;
+ unsigned long alloc_len, item_len;
+ unsigned char *where;
+ SECItem *item;
+ PRBool is_bit_string;
+
+ item_len = 0;
+ is_bit_string = (state->underlying_kind == SEC_ASN1_BIT_STRING)
+ ? PR_TRUE : PR_FALSE;
+
+ substring = state->subitems_head;
+ while (substring != NULL) {
+ /*
+ * All bit-string substrings except the last one should be
+ * a clean multiple of 8 bits.
+ */
+ if (is_bit_string && (substring->next == NULL)
+ && (substring->len & 0x7)) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return;
+ }
+ item_len += substring->len;
+ substring = substring->next;
+ }
+
+ if (is_bit_string) {
+#ifdef XP_WIN16 /* win16 compiler gets an internal error otherwise */
+ alloc_len = (((long)item_len + 7) / 8);
+#else
+ alloc_len = ((item_len + 7) >> 3);
+#endif
+ } else {
+ /*
+ * Add 2 for the end-of-contents octets of an indefinite-length
+ * ANY that is *not* also an INNER. Because we zero-allocate
+ * below, all we need to do is increase the length here.
+ */
+ if (state->underlying_kind == SEC_ASN1_ANY && state->indefinite)
+ item_len += 2;
+ alloc_len = item_len;
+ }
+
+ item = (SECItem *)(state->dest);
+ PORT_Assert (item != NULL);
+ PORT_Assert (item->data == NULL);
+ item->data = (unsigned char*)sec_asn1d_zalloc (state->top->their_pool,
+ alloc_len);
+ if (item->data == NULL) {
+ state->top->status = decodeError;
+ return;
+ }
+ item->len = item_len;
+
+ where = item->data;
+ substring = state->subitems_head;
+ while (substring != NULL) {
+ if (is_bit_string)
+ item_len = (substring->len + 7) >> 3;
+ else
+ item_len = substring->len;
+ PORT_Memcpy (where, substring->data, item_len);
+ where += item_len;
+ substring = substring->next;
+ }
+
+ /*
+ * Because we use arenas and have a mark set, we later free
+ * everything we have allocated, so this does *not* present
+ * a memory leak (it is just temporarily left dangling).
+ */
+ state->subitems_head = state->subitems_tail = NULL;
+ }
+
+ state->place = afterEndOfContents;
+}
+
+
+static void
+sec_asn1d_concat_group (sec_asn1d_state *state)
+{
+ const void ***placep;
+
+ PORT_Assert (state->place == afterGroup);
+
+ placep = (const void***)state->dest;
+ PORT_Assert(state->subitems_head == NULL || placep != NULL);
+ if (placep != NULL) {
+ struct subitem *item;
+ const void **group;
+ int count;
+
+ count = 0;
+ item = state->subitems_head;
+ while (item != NULL) {
+ PORT_Assert (item->next != NULL || item == state->subitems_tail);
+ count++;
+ item = item->next;
+ }
+
+ group = (const void**)sec_asn1d_zalloc (state->top->their_pool,
+ (count + 1) * (sizeof(void *)));
+ if (group == NULL) {
+ state->top->status = decodeError;
+ return;
+ }
+
+ *placep = group;
+
+ item = state->subitems_head;
+ while (item != NULL) {
+ *group++ = item->data;
+ item = item->next;
+ }
+ *group = NULL;
+
+ /*
+ * Because we use arenas and have a mark set, we later free
+ * everything we have allocated, so this does *not* present
+ * a memory leak (it is just temporarily left dangling).
+ */
+ state->subitems_head = state->subitems_tail = NULL;
+ }
+
+ state->place = afterEndOfContents;
+}
+
+
+/*
+ * For those states that push a child to handle a subtemplate,
+ * "absorb" that child (transfer necessary information).
+ */
+static void
+sec_asn1d_absorb_child (sec_asn1d_state *state)
+{
+ /*
+ * There is absolutely supposed to be a child there.
+ */
+ PORT_Assert (state->child != NULL);
+
+ /*
+ * Inherit the missing status of our child, and do the ugly
+ * backing-up if necessary.
+ */
+ state->missing = state->child->missing;
+ if (state->missing) {
+ state->found_tag_number = state->child->found_tag_number;
+ state->found_tag_modifiers = state->child->found_tag_modifiers;
+ state->endofcontents = state->child->endofcontents;
+ }
+
+ /*
+ * Add in number of bytes consumed by child.
+ * (Only EXPLICIT should have already consumed bytes itself.)
+ */
+ PORT_Assert (state->place == afterExplicit || state->consumed == 0);
+ state->consumed += state->child->consumed;
+
+ /*
+ * Subtract from bytes pending; this only applies to a definite-length
+ * EXPLICIT field.
+ */
+ if (state->pending) {
+ PORT_Assert (!state->indefinite);
+ PORT_Assert (state->place == afterExplicit);
+
+ /*
+ * If we had a definite-length explicit, then what the child
+ * consumed should be what was left pending.
+ */
+ if (state->pending != state->child->consumed) {
+ if (state->pending < state->child->consumed) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return;
+ }
+ /*
+ * Okay, this is a hack. It *should* be an error whether
+ * pending is too big or too small, but it turns out that
+ * we had a bug in our *old* DER encoder that ended up
+ * counting an explicit header twice in the case where
+ * the underlying type was an ANY. So, because we cannot
+ * prevent receiving these (our own certificate server can
+ * send them to us), we need to be lenient and accept them.
+ * To do so, we need to pretend as if we read all of the
+ * bytes that the header said we would find, even though
+ * we actually came up short.
+ */
+ state->consumed += (state->pending - state->child->consumed);
+ }
+ state->pending = 0;
+ }
+
+ /*
+ * Indicate that we are done with child.
+ */
+ state->child->consumed = 0;
+
+ /*
+ * And move on to final state.
+ * (Technically everybody could move to afterEndOfContents except
+ * for an indefinite-length EXPLICIT; for simplicity though we assert
+ * that but let the end-of-contents code do the real determination.)
+ */
+ PORT_Assert (state->place == afterExplicit || (! state->indefinite));
+ state->place = beforeEndOfContents;
+}
+
+
+static void
+sec_asn1d_prepare_for_end_of_contents (sec_asn1d_state *state)
+{
+ PORT_Assert (state->place == beforeEndOfContents);
+
+ if (state->indefinite) {
+ state->place = duringEndOfContents;
+ state->pending = 2;
+ } else {
+ state->place = afterEndOfContents;
+ }
+}
+
+
+static unsigned long
+sec_asn1d_parse_end_of_contents (sec_asn1d_state *state,
+ const char *buf, unsigned long len)
+{
+ unsigned int i;
+
+ PORT_Assert (state->pending <= 2);
+ PORT_Assert (state->place == duringEndOfContents);
+
+ if (len == 0) {
+ state->top->status = needBytes;
+ return 0;
+ }
+
+ if (state->pending < len)
+ len = state->pending;
+
+ for (i = 0; i < len; i++) {
+ if (buf[i] != 0) {
+ /*
+ * We expect to find only zeros; if not, just give up.
+ */
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return 0;
+ }
+ }
+
+ state->pending -= len;
+
+ if (state->pending == 0) {
+ state->place = afterEndOfContents;
+ state->endofcontents = PR_TRUE;
+ }
+
+ return len;
+}
+
+
+static void
+sec_asn1d_pop_state (sec_asn1d_state *state)
+{
+#if 0 /* XXX I think this should always be handled explicitly by parent? */
+ /*
+ * Account for our child.
+ */
+ if (state->child != NULL) {
+ state->consumed += state->child->consumed;
+ if (state->pending) {
+ PORT_Assert (!state->indefinite);
+ if (state->child->consumed > state->pending) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ } else {
+ state->pending -= state->child->consumed;
+ }
+ }
+ state->child->consumed = 0;
+ }
+#endif /* XXX */
+
+ /*
+ * Free our child.
+ */
+ sec_asn1d_free_child (state, PR_FALSE);
+
+ /*
+ * Just make my parent be the current state. It will then clean
+ * up after me and free me (or reuse me).
+ */
+ state->top->current = state->parent;
+}
+
+static sec_asn1d_state *
+sec_asn1d_before_choice (sec_asn1d_state *state)
+{
+ sec_asn1d_state *child;
+
+ if (state->allocate) {
+ void *dest;
+
+ dest = sec_asn1d_zalloc(state->top->their_pool, state->theTemplate->size);
+ if ((void *)NULL == dest) {
+ state->top->status = decodeError;
+ return (sec_asn1d_state *)NULL;
+ }
+
+ state->dest = (char *)dest + state->theTemplate->offset;
+ }
+
+ child = sec_asn1d_push_state(state->top, state->theTemplate + 1,
+ (char *)state->dest - state->theTemplate->offset,
+ PR_FALSE);
+ if ((sec_asn1d_state *)NULL == child) {
+ return (sec_asn1d_state *)NULL;
+ }
+
+ sec_asn1d_scrub_state(child);
+ child = sec_asn1d_init_state_based_on_template(child);
+ if ((sec_asn1d_state *)NULL == child) {
+ return (sec_asn1d_state *)NULL;
+ }
+
+ child->optional = PR_TRUE;
+
+ state->place = duringChoice;
+
+ return child;
+}
+
+static sec_asn1d_state *
+sec_asn1d_during_choice (sec_asn1d_state *state)
+{
+ sec_asn1d_state *child = state->child;
+
+ PORT_Assert((sec_asn1d_state *)NULL != child);
+
+ if (child->missing) {
+ unsigned char child_found_tag_modifiers = 0;
+ unsigned long child_found_tag_number = 0;
+ void * dest;
+
+ state->consumed += child->consumed;
+
+ if (child->endofcontents) {
+ /* This choice is probably the first item in a GROUP
+ ** (e.g. SET_OF) that was indefinite-length encoded.
+ ** We're actually at the end of that GROUP.
+ ** We look up the stack to be sure that we find
+ ** a state with indefinite length encoding before we
+ ** find a state (like a SEQUENCE) that is definite.
+ */
+ child->place = notInUse;
+ state->place = afterChoice;
+ state->endofcontents = PR_TRUE; /* propagate this up */
+ if (sec_asn1d_parent_allows_EOC(state))
+ return state;
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return NULL;
+ }
+
+ dest = (char *)child->dest - child->theTemplate->offset;
+ child->theTemplate++;
+
+ if (0 == child->theTemplate->kind) {
+ /* Ran out of choices */
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return (sec_asn1d_state *)NULL;
+ }
+ child->dest = (char *)dest + child->theTemplate->offset;
+
+ /* cargo'd from next_in_sequence innards */
+ if (state->pending) {
+ PORT_Assert(!state->indefinite);
+ if (child->consumed > state->pending) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return NULL;
+ }
+ state->pending -= child->consumed;
+ if (0 == state->pending) {
+ /* XXX uh.. not sure if I should have stopped this
+ * from happening before. */
+ PORT_Assert(0);
+ PORT_SetError(SEC_ERROR_BAD_DER);
+ state->top->status = decodeError;
+ return (sec_asn1d_state *)NULL;
+ }
+ }
+
+ child->consumed = 0;
+ sec_asn1d_scrub_state(child);
+
+ /* move it on top again */
+ state->top->current = child;
+
+ child_found_tag_modifiers = child->found_tag_modifiers;
+ child_found_tag_number = child->found_tag_number;
+
+ child = sec_asn1d_init_state_based_on_template(child);
+ if ((sec_asn1d_state *)NULL == child) {
+ return (sec_asn1d_state *)NULL;
+ }
+
+ /* copy our findings to the new top */
+ child->found_tag_modifiers = child_found_tag_modifiers;
+ child->found_tag_number = child_found_tag_number;
+
+ child->optional = PR_TRUE;
+ child->place = afterIdentifier;
+
+ return child;
+ }
+ if ((void *)NULL != state->dest) {
+ /* Store the enum */
+ int *which = (int *)state->dest;
+ *which = (int)child->theTemplate->size;
+ }
+
+ child->place = notInUse;
+
+ state->place = afterChoice;
+ return state;
+}
+
+static void
+sec_asn1d_after_choice (sec_asn1d_state *state)
+{
+ state->consumed += state->child->consumed;
+ state->child->consumed = 0;
+ state->place = afterEndOfContents;
+ sec_asn1d_pop_state(state);
+}
+
+unsigned long
+sec_asn1d_uinteger(SECItem *src)
+{
+ unsigned long value;
+ int len;
+
+ if (src->len > 5 || (src->len > 4 && src->data[0] == 0))
+ return 0;
+
+ value = 0;
+ len = src->len;
+ while (len) {
+ value <<= 8;
+ value |= src->data[--len];
+ }
+ return value;
+}
+
+SECStatus
+SEC_ASN1DecodeInteger(SECItem *src, unsigned long *value)
+{
+ unsigned long v;
+ unsigned int i;
+
+ if (src == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (src->len > sizeof(unsigned long)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (src->data == NULL) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return SECFailure;
+ }
+
+ if (src->data[0] & 0x80)
+ v = -1; /* signed and negative - start with all 1's */
+ else
+ v = 0;
+
+ for (i= 0; i < src->len; i++) {
+ /* shift in next byte */
+ v <<= 8;
+ v |= src->data[i];
+ }
+ *value = v;
+ return SECSuccess;
+}
+
+#ifdef DEBUG_ASN1D_STATES
+static void
+dump_states(SEC_ASN1DecoderContext *cx)
+{
+ sec_asn1d_state *state;
+ char kindBuf[256];
+
+ for (state = cx->current; state->parent; state = state->parent) {
+ ;
+ }
+
+ for (; state; state = state->child) {
+ int i;
+ for (i = 0; i < state->depth; i++) {
+ printf(" ");
+ }
+
+ i = formatKind(state->theTemplate->kind, kindBuf);
+ printf("%s: tmpl %08x, kind%s",
+ (state == cx->current) ? "STATE" : "State",
+ state->theTemplate,
+ kindBuf);
+ printf(" %s", (state->place >= 0 && state->place <= notInUse)
+ ? place_names[ state->place ]
+ : "(undefined)");
+ if (!i)
+ printf(", expect 0x%02x",
+ state->expect_tag_number | state->expect_tag_modifiers);
+
+ printf("%s%s%s %d\n",
+ state->indefinite ? ", indef" : "",
+ state->missing ? ", miss" : "",
+ state->endofcontents ? ", EOC" : "",
+ state->pending
+ );
+ }
+
+ return;
+}
+#endif /* DEBUG_ASN1D_STATES */
+
+SECStatus
+SEC_ASN1DecoderUpdate (SEC_ASN1DecoderContext *cx,
+ const char *buf, unsigned long len)
+{
+ sec_asn1d_state *state = NULL;
+ unsigned long consumed;
+ SEC_ASN1EncodingPart what;
+ sec_asn1d_state *stateEnd = cx->current;
+
+ if (cx->status == needBytes)
+ cx->status = keepGoing;
+
+ while (cx->status == keepGoing) {
+ state = cx->current;
+ what = SEC_ASN1_Contents;
+ consumed = 0;
+#ifdef DEBUG_ASN1D_STATES
+ printf("\nPLACE = %s, next byte = 0x%02x, %08x[%d]\n",
+ (state->place >= 0 && state->place <= notInUse) ?
+ place_names[ state->place ] : "(undefined)",
+ (unsigned int)((unsigned char *)buf)[ consumed ],
+ buf, consumed);
+ dump_states(cx);
+#endif /* DEBUG_ASN1D_STATES */
+ switch (state->place) {
+ case beforeIdentifier:
+ consumed = sec_asn1d_parse_identifier (state, buf, len);
+ what = SEC_ASN1_Identifier;
+ break;
+ case duringIdentifier:
+ consumed = sec_asn1d_parse_more_identifier (state, buf, len);
+ what = SEC_ASN1_Identifier;
+ break;
+ case afterIdentifier:
+ sec_asn1d_confirm_identifier (state);
+ break;
+ case beforeLength:
+ consumed = sec_asn1d_parse_length (state, buf, len);
+ what = SEC_ASN1_Length;
+ break;
+ case duringLength:
+ consumed = sec_asn1d_parse_more_length (state, buf, len);
+ what = SEC_ASN1_Length;
+ break;
+ case afterLength:
+ sec_asn1d_prepare_for_contents (state);
+ break;
+ case beforeBitString:
+ consumed = sec_asn1d_parse_bit_string (state, buf, len);
+ break;
+ case duringBitString:
+ consumed = sec_asn1d_parse_more_bit_string (state, buf, len);
+ break;
+ case duringConstructedString:
+ sec_asn1d_next_substring (state);
+ break;
+ case duringGroup:
+ sec_asn1d_next_in_group (state);
+ break;
+ case duringLeaf:
+ consumed = sec_asn1d_parse_leaf (state, buf, len);
+ break;
+ case duringSaveEncoding:
+ sec_asn1d_reuse_encoding (state);
+ if (cx->status == decodeError) {
+ /* recursive call has already popped all states from stack.
+ ** Bail out quickly.
+ */
+ return SECFailure;
+ }
+ if (cx->status == needBytes) {
+ /* recursive call wanted more data. Fatal. Clean up below. */
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ cx->status = decodeError;
+ }
+ break;
+ case duringSequence:
+ sec_asn1d_next_in_sequence (state);
+ break;
+ case afterConstructedString:
+ sec_asn1d_concat_substrings (state);
+ break;
+ case afterExplicit:
+ case afterImplicit:
+ case afterInline:
+ case afterPointer:
+ sec_asn1d_absorb_child (state);
+ break;
+ case afterGroup:
+ sec_asn1d_concat_group (state);
+ break;
+ case afterSaveEncoding:
+ /* SEC_ASN1DecoderUpdate has called itself recursively to
+ ** decode SAVEd encoded data, and now is done decoding that.
+ ** Return to the calling copy of SEC_ASN1DecoderUpdate.
+ */
+ return SECSuccess;
+ case beforeEndOfContents:
+ sec_asn1d_prepare_for_end_of_contents (state);
+ break;
+ case duringEndOfContents:
+ consumed = sec_asn1d_parse_end_of_contents (state, buf, len);
+ what = SEC_ASN1_EndOfContents;
+ break;
+ case afterEndOfContents:
+ sec_asn1d_pop_state (state);
+ break;
+ case beforeChoice:
+ state = sec_asn1d_before_choice(state);
+ break;
+ case duringChoice:
+ state = sec_asn1d_during_choice(state);
+ break;
+ case afterChoice:
+ sec_asn1d_after_choice(state);
+ break;
+ case notInUse:
+ default:
+ /* This is not an error, but rather a plain old BUG! */
+ PORT_Assert (0);
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ cx->status = decodeError;
+ break;
+ }
+
+ if (cx->status == decodeError)
+ break;
+
+ /* We should not consume more than we have. */
+ PORT_Assert (consumed <= len);
+ if (consumed > len) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ cx->status = decodeError;
+ break;
+ }
+
+ /* It might have changed, so we have to update our local copy. */
+ state = cx->current;
+
+ /* If it is NULL, we have popped all the way to the top. */
+ if (state == NULL) {
+ PORT_Assert (consumed == 0);
+#if 0 /* XXX I want this here, but it seems that we have situations (like
+ * downloading a pkcs7 cert chain from some issuers) that give us a
+ * length which is greater than the entire encoding. So, we cannot
+ * have this be an error.
+ */
+ if (len > 0) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ cx->status = decodeError;
+ } else
+#endif
+ cx->status = allDone;
+ break;
+ }
+ else if (state->theTemplate->kind == SEC_ASN1_SKIP_REST) {
+ cx->status = allDone;
+ break;
+ }
+
+ if (consumed == 0)
+ continue;
+
+ /*
+ * The following check is specifically looking for an ANY
+ * that is *not* also an INNER, because we need to save aside
+ * all bytes in that case -- the contents parts will get
+ * handled like all other contents, and the end-of-contents
+ * bytes are added by the concat code, but the outer header
+ * bytes need to get saved too, so we do them explicitly here.
+ */
+ if (state->underlying_kind == SEC_ASN1_ANY
+ && !cx->filter_only && (what == SEC_ASN1_Identifier
+ || what == SEC_ASN1_Length)) {
+ sec_asn1d_record_any_header (state, buf, consumed);
+ }
+
+ /*
+ * We had some number of good, accepted bytes. If the caller
+ * has registered to see them, pass them along.
+ */
+ if (state->top->filter_proc != NULL) {
+ int depth;
+
+ depth = state->depth;
+ if (what == SEC_ASN1_EndOfContents && !state->indefinite) {
+ PORT_Assert (state->parent != NULL
+ && state->parent->indefinite);
+ depth--;
+ PORT_Assert (depth == state->parent->depth);
+ }
+ (* state->top->filter_proc) (state->top->filter_arg,
+ buf, consumed, depth, what);
+ }
+
+ state->consumed += consumed;
+ buf += consumed;
+ len -= consumed;
+ }
+
+ if (cx->status == decodeError) {
+ while (state != NULL && stateEnd->parent!=state) {
+ sec_asn1d_free_child (state, PR_TRUE);
+ state = state->parent;
+ }
+#ifdef SEC_ASN1D_FREE_ON_ERROR /*
+ * XXX This does not work because we can
+ * end up leaving behind dangling pointers
+ * to stuff that was allocated. In order
+ * to make this really work (which would
+ * be a good thing, I think), we need to
+ * keep track of every place/pointer that
+ * was allocated and make sure to NULL it
+ * out before we then free back to the mark.
+ */
+ if (cx->their_pool != NULL) {
+ PORT_Assert (cx->their_mark != NULL);
+ PORT_ArenaRelease (cx->their_pool, cx->their_mark);
+ }
+#endif
+ return SECFailure;
+ }
+
+#if 0 /* XXX This is what I want, but cannot have because it seems we
+ * have situations (like when downloading a pkcs7 cert chain from
+ * some issuers) that give us a total length which is greater than
+ * the entire encoding. So, we have to allow allDone to have a
+ * remaining length greater than zero. I wanted to catch internal
+ * bugs with this, noticing when we do not have the right length.
+ * Oh well.
+ */
+ PORT_Assert (len == 0
+ && (cx->status == needBytes || cx->status == allDone));
+#else
+ PORT_Assert ((len == 0 && cx->status == needBytes)
+ || cx->status == allDone);
+#endif
+ return SECSuccess;
+}
+
+
+SECStatus
+SEC_ASN1DecoderFinish (SEC_ASN1DecoderContext *cx)
+{
+ SECStatus rv;
+
+ if (cx->status == needBytes) {
+ PORT_SetError (SEC_ERROR_BAD_DER);
+ rv = SECFailure;
+ } else {
+ rv = SECSuccess;
+ }
+
+ /*
+ * XXX anything else that needs to be finished?
+ */
+
+ PORT_FreeArena (cx->our_pool, PR_TRUE);
+
+ return rv;
+}
+
+
+SEC_ASN1DecoderContext *
+SEC_ASN1DecoderStart (PRArenaPool *their_pool, void *dest,
+ const SEC_ASN1Template *theTemplate)
+{
+ PRArenaPool *our_pool;
+ SEC_ASN1DecoderContext *cx;
+
+ our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (our_pool == NULL)
+ return NULL;
+
+ cx = (SEC_ASN1DecoderContext*)PORT_ArenaZAlloc (our_pool, sizeof(*cx));
+ if (cx == NULL) {
+ PORT_FreeArena (our_pool, PR_FALSE);
+ return NULL;
+ }
+
+ cx->our_pool = our_pool;
+ if (their_pool != NULL) {
+ cx->their_pool = their_pool;
+#ifdef SEC_ASN1D_FREE_ON_ERROR
+ cx->their_mark = PORT_ArenaMark (their_pool);
+#endif
+ }
+
+ cx->status = needBytes;
+
+ if (sec_asn1d_push_state(cx, theTemplate, dest, PR_FALSE) == NULL
+ || sec_asn1d_init_state_based_on_template (cx->current) == NULL) {
+ /*
+ * Trouble initializing (probably due to failed allocations)
+ * requires that we just give up.
+ */
+ PORT_FreeArena (our_pool, PR_FALSE);
+ return NULL;
+ }
+
+ return cx;
+}
+
+
+void
+SEC_ASN1DecoderSetFilterProc (SEC_ASN1DecoderContext *cx,
+ SEC_ASN1WriteProc fn, void *arg,
+ PRBool only)
+{
+ /* check that we are "between" fields here */
+ PORT_Assert (cx->during_notify);
+
+ cx->filter_proc = fn;
+ cx->filter_arg = arg;
+ cx->filter_only = only;
+}
+
+
+void
+SEC_ASN1DecoderClearFilterProc (SEC_ASN1DecoderContext *cx)
+{
+ /* check that we are "between" fields here */
+ PORT_Assert (cx->during_notify);
+
+ cx->filter_proc = NULL;
+ cx->filter_arg = NULL;
+ cx->filter_only = PR_FALSE;
+}
+
+
+void
+SEC_ASN1DecoderSetNotifyProc (SEC_ASN1DecoderContext *cx,
+ SEC_ASN1NotifyProc fn, void *arg)
+{
+ cx->notify_proc = fn;
+ cx->notify_arg = arg;
+}
+
+
+void
+SEC_ASN1DecoderClearNotifyProc (SEC_ASN1DecoderContext *cx)
+{
+ cx->notify_proc = NULL;
+ cx->notify_arg = NULL; /* not necessary; just being clean */
+}
+
+void
+SEC_ASN1DecoderAbort(SEC_ASN1DecoderContext *cx, int error)
+{
+ PORT_Assert(cx);
+ PORT_SetError(error);
+ cx->status = decodeError;
+}
+
+
+SECStatus
+SEC_ASN1Decode (PRArenaPool *poolp, void *dest,
+ const SEC_ASN1Template *theTemplate,
+ const char *buf, long len)
+{
+ SEC_ASN1DecoderContext *dcx;
+ SECStatus urv, frv;
+
+ dcx = SEC_ASN1DecoderStart (poolp, dest, theTemplate);
+ if (dcx == NULL)
+ return SECFailure;
+
+ urv = SEC_ASN1DecoderUpdate (dcx, buf, len);
+ frv = SEC_ASN1DecoderFinish (dcx);
+
+ if (urv != SECSuccess)
+ return urv;
+
+ return frv;
+}
+
+
+SECStatus
+SEC_ASN1DecodeItem (PRArenaPool *poolp, void *dest,
+ const SEC_ASN1Template *theTemplate,
+ const SECItem *src)
+{
+ return SEC_ASN1Decode (poolp, dest, theTemplate,
+ (const char *)src->data, src->len);
+}
+
+#ifdef DEBUG_ASN1D_STATES
+void sec_asn1d_Assert(const char *s, const char *file, PRIntn ln)
+{
+ printf("Assertion failed, \"%s\", file %s, line %d\n", s, file, ln);
+ fflush(stdout);
+}
+#endif
+
+/*
+ * Generic templates for individual/simple items and pointers to
+ * and sets of same.
+ *
+ * If you need to add a new one, please note the following:
+ * - For each new basic type you should add *four* templates:
+ * one plain, one PointerTo, one SequenceOf and one SetOf.
+ * - If the new type can be constructed (meaning, it is a
+ * *string* type according to BER/DER rules), then you should
+ * or-in SEC_ASN1_MAY_STREAM to the type in the basic template.
+ * See the definition of the OctetString template for an example.
+ * - It may not be obvious, but these are in *alphabetical*
+ * order based on the SEC_ASN1_XXX name; so put new ones in
+ * the appropriate place.
+ */
+
+const SEC_ASN1Template SEC_SequenceOfAnyTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_AnyTemplate }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_PointerToBitStringTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_BitStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfBitStringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_BitStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfBitStringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_BitStringTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToBMPStringTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_BMPStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfBMPStringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_BMPStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfBMPStringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_BMPStringTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToBooleanTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_BooleanTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfBooleanTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_BooleanTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfBooleanTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_BooleanTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_EnumeratedTemplate[] = {
+ { SEC_ASN1_ENUMERATED, 0, NULL, sizeof(SECItem) }
+};
+
+const SEC_ASN1Template SEC_PointerToEnumeratedTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_EnumeratedTemplate }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_SequenceOfEnumeratedTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_EnumeratedTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_SetOfEnumeratedTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_EnumeratedTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToGeneralizedTimeTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_GeneralizedTimeTemplate }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_SequenceOfGeneralizedTimeTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_GeneralizedTimeTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfGeneralizedTimeTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_GeneralizedTimeTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToIA5StringTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_IA5StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfIA5StringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_IA5StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfIA5StringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_IA5StringTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToIntegerTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_IntegerTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfIntegerTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_IntegerTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfIntegerTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_IntegerTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToNullTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_NullTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfNullTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_NullTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfNullTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_NullTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToObjectIDTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_ObjectIDTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_SequenceOfObjectIDTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_ObjectIDTemplate }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_SetOfObjectIDTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_ObjectIDTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfOctetStringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_OctetStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfOctetStringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_OctetStringTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_PrintableStringTemplate[] = {
+ { SEC_ASN1_PRINTABLE_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_PointerToPrintableStringTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_PrintableStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfPrintableStringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_PrintableStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfPrintableStringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_PrintableStringTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_T61StringTemplate[] = {
+ { SEC_ASN1_T61_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_PointerToT61StringTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_T61StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfT61StringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_T61StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfT61StringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_T61StringTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_UniversalStringTemplate[] = {
+ { SEC_ASN1_UNIVERSAL_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_PointerToUniversalStringTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_UniversalStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfUniversalStringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_UniversalStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfUniversalStringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_UniversalStringTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToUTCTimeTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_UTCTimeTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfUTCTimeTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_UTCTimeTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfUTCTimeTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_UTCTimeTemplate }
+};
+
+const SEC_ASN1Template SEC_PointerToUTF8StringTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_UTF8StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfUTF8StringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_UTF8StringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfUTF8StringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_UTF8StringTemplate }
+};
+
+#endif
+
+const SEC_ASN1Template SEC_VisibleStringTemplate[] = {
+ { SEC_ASN1_VISIBLE_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+#if 0
+
+const SEC_ASN1Template SEC_PointerToVisibleStringTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_VisibleStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SequenceOfVisibleStringTemplate[] = {
+ { SEC_ASN1_SEQUENCE_OF, 0, SEC_VisibleStringTemplate }
+};
+
+const SEC_ASN1Template SEC_SetOfVisibleStringTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_VisibleStringTemplate }
+};
+
+#endif
+
+/*
+ * Template for skipping a subitem.
+ *
+ * Note that it only makes sense to use this for decoding (when you want
+ * to decode something where you are only interested in one or two of
+ * the fields); you cannot encode a SKIP!
+ */
+const SEC_ASN1Template SEC_SkipTemplate[] = {
+ { SEC_ASN1_SKIP }
+};
+
+
+/* These functions simply return the address of the above-declared templates.
+** This is necessary for Windows DLLs. Sigh.
+*/
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_EnumeratedTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PointerToEnumeratedTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SequenceOfAnyTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SequenceOfObjectIDTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SkipTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_UniversalStringTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PrintableStringTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_T61StringTemplate)
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PointerToGeneralizedTimeTemplate)
+
diff --git a/security/nss/lib/util/secasn1e.c b/security/nss/lib/util/secasn1e.c
new file mode 100644
index 000000000..2300060df
--- /dev/null
+++ b/security/nss/lib/util/secasn1e.c
@@ -0,0 +1,1647 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Support for ENcoding ASN.1 data based on BER/DER (Basic/Distinguished
+ * Encoding Rules).
+ *
+ * $Id$
+ */
+
+#include "secasn1.h"
+
+typedef enum {
+ beforeHeader,
+ duringContents,
+ duringGroup,
+ duringSequence,
+ afterContents,
+ afterImplicit,
+ afterInline,
+ afterPointer,
+ afterChoice,
+ notInUse
+} sec_asn1e_parse_place;
+
+typedef enum {
+ allDone,
+ encodeError,
+ keepGoing,
+ needBytes
+} sec_asn1e_parse_status;
+
+typedef enum {
+ hdr_normal = 0, /* encode header normally */
+ hdr_any = 1, /* header already encoded in content */
+ hdr_decoder = 2, /* template only used by decoder. skip it. */
+ hdr_optional = 3, /* optional component, to be omitted */
+ hdr_placeholder = 4 /* place holder for from_buf content */
+} sec_asn1e_hdr_encoding;
+
+typedef struct sec_asn1e_state_struct {
+ SEC_ASN1EncoderContext *top;
+ const SEC_ASN1Template *theTemplate;
+ void *src;
+
+ struct sec_asn1e_state_struct *parent; /* aka prev */
+ struct sec_asn1e_state_struct *child; /* aka next */
+
+ sec_asn1e_parse_place place; /* where we are in encoding process */
+
+ /*
+ * XXX explain the next fields as clearly as possible...
+ */
+ unsigned char tag_modifiers;
+ unsigned char tag_number;
+ unsigned long underlying_kind;
+
+ int depth;
+
+ PRBool isExplicit, /* we are handling an isExplicit header */
+ indefinite, /* need end-of-contents */
+ is_string, /* encoding a simple string or an ANY */
+ may_stream, /* when streaming, do indefinite encoding */
+ optional, /* omit field if it has no contents */
+ disallowStreaming; /* disallow streaming in all sub-templates */
+} sec_asn1e_state;
+
+/*
+ * An "outsider" will have an opaque pointer to this, created by calling
+ * SEC_ASN1EncoderStart(). It will be passed back in to all subsequent
+ * calls to SEC_ASN1EncoderUpdate() and related routines, and when done
+ * it is passed to SEC_ASN1EncoderFinish().
+ */
+struct sec_EncoderContext_struct {
+ PRArenaPool *our_pool; /* for our internal allocs */
+
+ sec_asn1e_state *current;
+ sec_asn1e_parse_status status;
+
+ PRBool streaming;
+ PRBool from_buf;
+
+ SEC_ASN1NotifyProc notify_proc; /* call before/after handling field */
+ void *notify_arg; /* argument to notify_proc */
+ PRBool during_notify; /* true during call to notify_proc */
+
+ SEC_ASN1WriteProc output_proc; /* pass encoded bytes to this */
+ void *output_arg; /* argument to that function */
+};
+
+
+static sec_asn1e_state *
+sec_asn1e_push_state (SEC_ASN1EncoderContext *cx,
+ const SEC_ASN1Template *theTemplate,
+ const void *src, PRBool new_depth)
+{
+ sec_asn1e_state *state, *new_state;
+
+ state = cx->current;
+
+ new_state = (sec_asn1e_state*)PORT_ArenaZAlloc (cx->our_pool,
+ sizeof(*new_state));
+ if (new_state == NULL) {
+ cx->status = encodeError;
+ return NULL;
+ }
+
+ new_state->top = cx;
+ new_state->parent = state;
+ new_state->theTemplate = theTemplate;
+ new_state->place = notInUse;
+ if (src != NULL)
+ new_state->src = (char *)src + theTemplate->offset;
+
+ if (state != NULL) {
+ new_state->depth = state->depth;
+ if (new_depth)
+ new_state->depth++;
+ state->child = new_state;
+ }
+
+ cx->current = new_state;
+ return new_state;
+}
+
+
+static void
+sec_asn1e_scrub_state (sec_asn1e_state *state)
+{
+ /*
+ * Some default "scrubbing".
+ * XXX right set of initializations?
+ */
+ state->place = beforeHeader;
+ state->indefinite = PR_FALSE;
+}
+
+
+static void
+sec_asn1e_notify_before (SEC_ASN1EncoderContext *cx, void *src, int depth)
+{
+ if (cx->notify_proc == NULL)
+ return;
+
+ cx->during_notify = PR_TRUE;
+ (* cx->notify_proc) (cx->notify_arg, PR_TRUE, src, depth);
+ cx->during_notify = PR_FALSE;
+}
+
+
+static void
+sec_asn1e_notify_after (SEC_ASN1EncoderContext *cx, void *src, int depth)
+{
+ if (cx->notify_proc == NULL)
+ return;
+
+ cx->during_notify = PR_TRUE;
+ (* cx->notify_proc) (cx->notify_arg, PR_FALSE, src, depth);
+ cx->during_notify = PR_FALSE;
+}
+
+
+static sec_asn1e_state *
+sec_asn1e_init_state_based_on_template (sec_asn1e_state *state)
+{
+ PRBool isExplicit, is_string, may_stream, optional, universal;
+ PRBool disallowStreaming;
+ unsigned char tag_modifiers;
+ unsigned long encode_kind, under_kind;
+ unsigned long tag_number;
+ PRBool isInline = PR_FALSE;
+
+
+ encode_kind = state->theTemplate->kind;
+
+ universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
+ ? PR_TRUE : PR_FALSE;
+
+ isExplicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_EXPLICIT;
+
+ optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_OPTIONAL;
+
+ PORT_Assert (!(isExplicit && universal)); /* bad templates */
+
+ may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_MAY_STREAM;
+
+ disallowStreaming = (encode_kind & SEC_ASN1_NO_STREAM) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_NO_STREAM;
+
+ /* Just clear this to get it out of the way; we do not need it here */
+ encode_kind &= ~SEC_ASN1_DYNAMIC;
+
+ if( encode_kind & SEC_ASN1_CHOICE ) {
+ under_kind = SEC_ASN1_CHOICE;
+ } else if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) ||
+ (!universal && !isExplicit)) {
+ const SEC_ASN1Template *subt;
+ void *src = NULL;
+
+ PORT_Assert ((encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) == 0);
+
+ sec_asn1e_scrub_state (state);
+
+ if (encode_kind & SEC_ASN1_POINTER) {
+ src = *(void **)state->src;
+ state->place = afterPointer;
+
+ if (src == NULL) {
+ /*
+ * If this is optional, but NULL, then the field does
+ * not need to be encoded. In this case we are done;
+ * we do not want to push a subtemplate.
+ */
+ if (optional)
+ return state;
+
+ /*
+ * XXX this is an error; need to figure out
+ * how to handle this
+ */
+ }
+ } else {
+ src = state->src;
+ if (encode_kind & SEC_ASN1_INLINE) {
+ /* check that there are no extraneous bits */
+ /* PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional); */
+ state->place = afterInline;
+ isInline = PR_TRUE;
+ } else {
+ /*
+ * Save the tag modifiers and tag number here before moving
+ * on to the next state in case this is a member of a
+ * SEQUENCE OF
+ */
+ state->tag_modifiers = (unsigned char)
+ (encode_kind & (SEC_ASN1_TAG_MASK & ~SEC_ASN1_TAGNUM_MASK));
+ state->tag_number = (unsigned char)
+ (encode_kind & SEC_ASN1_TAGNUM_MASK);
+
+ state->place = afterImplicit;
+ state->optional = optional;
+ }
+ }
+
+ subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src, PR_TRUE);
+ if (isInline && optional) {
+ /* we only handle a very limited set of optional inline cases at
+ this time */
+ if (PR_FALSE != SEC_ASN1IsTemplateSimple(subt)) {
+ /* we now know that the target is a SECItem*, so we can check
+ if the source contains one */
+ SECItem* target = (SECItem*)state->src;
+ if (!target || !target->data || !target->len) {
+ /* no valid data to encode subtemplate */
+ return state;
+ }
+ } else {
+ PORT_Assert(0); /* complex templates are not handled as
+ inline optional */
+ }
+ }
+ state = sec_asn1e_push_state (state->top, subt, src, PR_FALSE);
+ if (state == NULL)
+ return state;
+
+ if (universal) {
+ /*
+ * This is a POINTER or INLINE; just init based on that
+ * and we are done.
+ */
+ return sec_asn1e_init_state_based_on_template (state);
+ }
+
+ /*
+ * This is an implicit, non-universal (meaning, application-private
+ * or context-specific) field. This results in a "magic" tag but
+ * encoding based on the underlying type. We pushed a new state
+ * that is based on the subtemplate (the underlying type), but
+ * now we will sort of alias it to give it some of our properties
+ * (tag, optional status, etc.).
+ *
+ * NB: ALL the following flags in the subtemplate are disallowed
+ * and/or ignored: EXPLICIT, OPTIONAL, INNER, INLINE, POINTER.
+ */
+
+ under_kind = state->theTemplate->kind;
+ if ((under_kind & SEC_ASN1_MAY_STREAM) && !disallowStreaming) {
+ may_stream = PR_TRUE;
+ }
+ under_kind &= ~(SEC_ASN1_MAY_STREAM | SEC_ASN1_DYNAMIC);
+ } else {
+ under_kind = encode_kind;
+ }
+
+ /*
+ * Sanity check that there are no unwanted bits marked in under_kind.
+ * These bits were either removed above (after we recorded them) or
+ * they simply should not be found (signalling a bad/broken template).
+ * XXX is this the right set of bits to test here? (i.e. need to add
+ * or remove any?)
+ */
+#define UNEXPECTED_FLAGS \
+ (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_SKIP | SEC_ASN1_INNER | \
+ SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM | SEC_ASN1_INLINE | SEC_ASN1_POINTER)
+
+ PORT_Assert ((under_kind & UNEXPECTED_FLAGS) == 0);
+ under_kind &= ~UNEXPECTED_FLAGS;
+#undef UNEXPECTED_FLAGS
+
+ if (encode_kind & SEC_ASN1_ANY) {
+ PORT_Assert (encode_kind == under_kind);
+ tag_modifiers = 0;
+ tag_number = 0;
+ is_string = PR_TRUE;
+ } else {
+ tag_modifiers = (unsigned char)
+ (encode_kind & (SEC_ASN1_TAG_MASK & ~SEC_ASN1_TAGNUM_MASK));
+ /*
+ * XXX This assumes only single-octet identifiers. To handle
+ * the HIGH TAG form we would need to do some more work, especially
+ * in how to specify them in the template, because right now we
+ * do not provide a way to specify more *tag* bits in encode_kind.
+ */
+ tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK;
+
+ is_string = PR_FALSE;
+ switch (under_kind & SEC_ASN1_TAGNUM_MASK) {
+ case SEC_ASN1_SET:
+ /*
+ * XXX A plain old SET (as opposed to a SET OF) is not implemented.
+ * If it ever is, remove this assert...
+ */
+ PORT_Assert ((under_kind & SEC_ASN1_GROUP) != 0);
+ /* fallthru */
+ case SEC_ASN1_SEQUENCE:
+ tag_modifiers |= SEC_ASN1_CONSTRUCTED;
+ break;
+ case SEC_ASN1_BIT_STRING:
+ case SEC_ASN1_BMP_STRING:
+ case SEC_ASN1_GENERALIZED_TIME:
+ case SEC_ASN1_IA5_STRING:
+ case SEC_ASN1_OCTET_STRING:
+ case SEC_ASN1_PRINTABLE_STRING:
+ case SEC_ASN1_T61_STRING:
+ case SEC_ASN1_UNIVERSAL_STRING:
+ case SEC_ASN1_UTC_TIME:
+ case SEC_ASN1_UTF8_STRING:
+ case SEC_ASN1_VISIBLE_STRING:
+ /*
+ * We do not yet know if we will be constructing the string,
+ * so we have to wait to do this final tag modification.
+ */
+ is_string = PR_TRUE;
+ break;
+ }
+ }
+
+ state->tag_modifiers = tag_modifiers;
+ state->tag_number = (unsigned char)tag_number;
+ state->underlying_kind = under_kind;
+ state->isExplicit = isExplicit;
+ state->may_stream = may_stream;
+ state->is_string = is_string;
+ state->optional = optional;
+ state->disallowStreaming = disallowStreaming;
+
+ sec_asn1e_scrub_state (state);
+
+ return state;
+}
+
+
+static void
+sec_asn1e_write_part (sec_asn1e_state *state,
+ const char *buf, unsigned long len,
+ SEC_ASN1EncodingPart part)
+{
+ SEC_ASN1EncoderContext *cx;
+
+ cx = state->top;
+ (* cx->output_proc) (cx->output_arg, buf, len, state->depth, part);
+}
+
+
+/*
+ * XXX This assumes only single-octet identifiers. To handle
+ * the HIGH TAG form we would need to modify this interface and
+ * teach it to properly encode the special form.
+ */
+static void
+sec_asn1e_write_identifier_bytes (sec_asn1e_state *state, unsigned char value)
+{
+ char byte;
+
+ byte = (char) value;
+ sec_asn1e_write_part (state, &byte, 1, SEC_ASN1_Identifier);
+}
+
+int
+SEC_ASN1EncodeLength(unsigned char *buf,int value) {
+ int lenlen;
+
+ lenlen = SEC_ASN1LengthLength (value);
+ if (lenlen == 1) {
+ buf[0] = value;
+ } else {
+ int i;
+
+ i = lenlen - 1;
+ buf[0] = 0x80 | i;
+ while (i) {
+ buf[i--] = value;
+ value >>= 8;
+ }
+ PORT_Assert (value == 0);
+ }
+ return lenlen;
+}
+
+static void
+sec_asn1e_write_length_bytes (sec_asn1e_state *state, unsigned long value,
+ PRBool indefinite)
+{
+ int lenlen;
+ unsigned char buf[sizeof(unsigned long) + 1];
+
+ if (indefinite) {
+ PORT_Assert (value == 0);
+ buf[0] = 0x80;
+ lenlen = 1;
+ } else {
+ lenlen = SEC_ASN1EncodeLength(buf,value);
+ }
+
+ sec_asn1e_write_part (state, (char *) buf, lenlen, SEC_ASN1_Length);
+}
+
+
+static void
+sec_asn1e_write_contents_bytes (sec_asn1e_state *state,
+ const char *buf, unsigned long len)
+{
+ sec_asn1e_write_part (state, buf, len, SEC_ASN1_Contents);
+}
+
+
+static void
+sec_asn1e_write_end_of_contents_bytes (sec_asn1e_state *state)
+{
+ const char eoc[2] = {0, 0};
+
+ sec_asn1e_write_part (state, eoc, 2, SEC_ASN1_EndOfContents);
+}
+
+static int
+sec_asn1e_which_choice
+(
+ void *src,
+ const SEC_ASN1Template *theTemplate
+)
+{
+ int rv;
+ unsigned int which = *(unsigned int *)src;
+
+ for( rv = 1, theTemplate++; theTemplate->kind != 0; rv++, theTemplate++ ) {
+ if( which == theTemplate->size ) {
+ return rv;
+ }
+ }
+
+ return 0;
+}
+
+static unsigned long
+sec_asn1e_contents_length (const SEC_ASN1Template *theTemplate, void *src,
+ PRBool disallowStreaming, PRBool insideIndefinite,
+ sec_asn1e_hdr_encoding *pHdrException)
+{
+ unsigned long encode_kind, underlying_kind;
+ PRBool isExplicit, optional, universal, may_stream;
+ unsigned long len;
+
+ /*
+ * This function currently calculates the length in all cases
+ * except the following: when writing out the contents of a
+ * template that belongs to a state where it was a sub-template
+ * with the SEC_ASN1_MAY_STREAM bit set and it's parent had the
+ * optional bit set. The information that the parent is optional
+ * and that we should return the length of 0 when that length is
+ * present since that means the optional field is no longer present.
+ * So we add the disallowStreaming flag which is passed in when
+ * writing the contents, but for all recursive calls to
+ * sec_asn1e_contents_length, we pass PR_FALSE, because this
+ * function correctly calculates the length for children templates
+ * from that point on. Confused yet? At least you didn't have
+ * to figure it out. ;) -javi
+ */
+ encode_kind = theTemplate->kind;
+
+ universal = ((encode_kind & SEC_ASN1_CLASS_MASK) == SEC_ASN1_UNIVERSAL)
+ ? PR_TRUE : PR_FALSE;
+
+ isExplicit = (encode_kind & SEC_ASN1_EXPLICIT) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_EXPLICIT;
+
+ optional = (encode_kind & SEC_ASN1_OPTIONAL) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_OPTIONAL;
+
+ PORT_Assert (!(isExplicit && universal)); /* bad templates */
+
+ may_stream = (encode_kind & SEC_ASN1_MAY_STREAM) ? PR_TRUE : PR_FALSE;
+ encode_kind &= ~SEC_ASN1_MAY_STREAM;
+
+ /* Just clear this to get it out of the way; we do not need it here */
+ encode_kind &= ~SEC_ASN1_DYNAMIC;
+
+ if (encode_kind & SEC_ASN1_NO_STREAM) {
+ disallowStreaming = PR_TRUE;
+ }
+ encode_kind &= ~SEC_ASN1_NO_STREAM;
+
+ if (encode_kind & SEC_ASN1_CHOICE) {
+ void *src2;
+ int indx = sec_asn1e_which_choice(src, theTemplate);
+ if (0 == indx) {
+ /* XXX set an error? "choice not found" */
+ /* state->top->status = encodeError; */
+ return 0;
+ }
+
+ src2 = (void *)
+ ((char *)src - theTemplate->offset + theTemplate[indx].offset);
+
+ return sec_asn1e_contents_length(&theTemplate[indx], src2,
+ disallowStreaming, insideIndefinite,
+ pHdrException);
+ }
+
+ if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || !universal) {
+ /* XXX any bits we want to disallow (PORT_Assert against) here? */
+ theTemplate = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE);
+ if (encode_kind & SEC_ASN1_POINTER) {
+ src = *(void **)src;
+ if (src == NULL) {
+ *pHdrException = optional ? hdr_optional : hdr_normal;
+ return 0;
+ }
+ } else if (encode_kind & SEC_ASN1_INLINE) {
+ /* check that there are no extraneous bits */
+ if (optional) {
+ if (PR_FALSE != SEC_ASN1IsTemplateSimple(theTemplate)) {
+ /* we now know that the target is a SECItem*, so we can check
+ if the source contains one */
+ SECItem* target = (SECItem*)src;
+ if (!target || !target->data || !target->len) {
+ /* no valid data to encode subtemplate */
+ *pHdrException = hdr_optional;
+ return 0;
+ }
+ } else {
+ PORT_Assert(0); /* complex templates not handled as inline
+ optional */
+ }
+ }
+ }
+
+ src = (char *)src + theTemplate->offset;
+
+ /* recurse to find the length of the subtemplate */
+ len = sec_asn1e_contents_length (theTemplate, src, disallowStreaming,
+ insideIndefinite, pHdrException);
+ if (len == 0 && optional) {
+ *pHdrException = hdr_optional;
+ } else if (isExplicit) {
+ if (*pHdrException == hdr_any) {
+ /* *we* do not want to add in a header,
+ ** but our caller still does.
+ */
+ *pHdrException = hdr_normal;
+ } else if (*pHdrException == hdr_normal) {
+ /* if the inner content exists, our length is
+ * len(identifier) + len(length) + len(innercontent)
+ * XXX we currently assume len(identifier) == 1;
+ * to support a high-tag-number this would need to be smarter.
+ */
+ len += 1 + SEC_ASN1LengthLength (len);
+ }
+ }
+ return len;
+ }
+ underlying_kind = encode_kind;
+
+ /* This is only used in decoding; it plays no part in encoding. */
+ if (underlying_kind & SEC_ASN1_SAVE) {
+ /* check that there are no extraneous bits */
+ PORT_Assert (underlying_kind == SEC_ASN1_SAVE);
+ *pHdrException = hdr_decoder;
+ return 0;
+ }
+
+#define UNEXPECTED_FLAGS \
+ (SEC_ASN1_EXPLICIT | SEC_ASN1_OPTIONAL | SEC_ASN1_INLINE | SEC_ASN1_POINTER |\
+ SEC_ASN1_DYNAMIC | SEC_ASN1_MAY_STREAM | SEC_ASN1_SAVE | SEC_ASN1_SKIP)
+
+ /* Having any of these bits is not expected here... */
+ PORT_Assert ((underlying_kind & UNEXPECTED_FLAGS) == 0);
+ underlying_kind &= ~UNEXPECTED_FLAGS;
+#undef UNEXPECTED_FLAGS
+
+ if (underlying_kind & SEC_ASN1_CHOICE) {
+ void *src2;
+ int indx = sec_asn1e_which_choice(src, theTemplate);
+ if (0 == indx) {
+ /* XXX set an error? "choice not found" */
+ /* state->top->status = encodeError; */
+ return 0;
+ }
+
+ src2 = (void *)
+ ((char *)src - theTemplate->offset + theTemplate[indx].offset);
+ len = sec_asn1e_contents_length(&theTemplate[indx], src2,
+ disallowStreaming, insideIndefinite,
+ pHdrException);
+ } else {
+ switch (underlying_kind) {
+ case SEC_ASN1_SEQUENCE_OF:
+ case SEC_ASN1_SET_OF:
+ {
+ const SEC_ASN1Template *tmpt;
+ void *sub_src;
+ unsigned long sub_len;
+ void **group;
+
+ len = 0;
+
+ group = *(void ***)src;
+ if (group == NULL)
+ break;
+
+ tmpt = SEC_ASN1GetSubtemplate (theTemplate, src, PR_TRUE);
+
+ for (; *group != NULL; group++) {
+ sub_src = (char *)(*group) + tmpt->offset;
+ sub_len = sec_asn1e_contents_length (tmpt, sub_src,
+ disallowStreaming,
+ insideIndefinite,
+ pHdrException);
+ len += sub_len;
+ /*
+ * XXX The 1 below is the presumed length of the identifier;
+ * to support a high-tag-number this would need to be smarter.
+ */
+ if (*pHdrException == hdr_normal)
+ len += 1 + SEC_ASN1LengthLength (sub_len);
+ }
+ }
+ break;
+
+ case SEC_ASN1_SEQUENCE:
+ case SEC_ASN1_SET:
+ {
+ const SEC_ASN1Template *tmpt;
+ void *sub_src;
+ unsigned long sub_len;
+
+ len = 0;
+ for (tmpt = theTemplate + 1; tmpt->kind; tmpt++) {
+ sub_src = (char *)src + tmpt->offset;
+ sub_len = sec_asn1e_contents_length (tmpt, sub_src,
+ disallowStreaming,
+ insideIndefinite,
+ pHdrException);
+ len += sub_len;
+ /*
+ * XXX The 1 below is the presumed length of the identifier;
+ * to support a high-tag-number this would need to be smarter.
+ */
+ if (*pHdrException == hdr_normal)
+ len += 1 + SEC_ASN1LengthLength (sub_len);
+ }
+ }
+ break;
+
+ case SEC_ASN1_BIT_STRING:
+ /* convert bit length to byte */
+ len = (((SECItem *)src)->len + 7) >> 3;
+ /* bit string contents involve an extra octet */
+ if (len)
+ len++;
+ break;
+
+ case SEC_ASN1_INTEGER:
+ /* ASN.1 INTEGERs are signed.
+ * If the source is an unsigned integer, the encoder will need
+ * to handle the conversion here.
+ */
+ {
+ unsigned char *buf = ((SECItem *)src)->data;
+ SECItemType integerType = ((SECItem *)src)->type;
+ len = ((SECItem *)src)->len;
+ while (len > 0) {
+ if (*buf != 0) {
+ if (*buf & 0x80 && integerType == siUnsignedInteger) {
+ len++; /* leading zero needed to make number signed */
+ }
+ break; /* reached beginning of number */
+ }
+ if (len == 1) {
+ break; /* the number 0 */
+ }
+ if (buf[1] & 0x80) {
+ break; /* leading zero already present */
+ }
+ /* extraneous leading zero, keep going */
+ buf++;
+ len--;
+ }
+ }
+ break;
+
+ default:
+ len = ((SECItem *)src)->len;
+ break;
+ } /* end switch */
+
+#ifndef WHAT_PROBLEM_DOES_THIS_SOLVE
+ /* if we're streaming, we may have a secitem w/len 0 as placeholder */
+ if (!len && insideIndefinite && may_stream && !disallowStreaming) {
+ len = 1;
+ }
+#endif
+ } /* end else */
+
+ if (len == 0 && optional)
+ *pHdrException = hdr_optional;
+ else if (underlying_kind == SEC_ASN1_ANY)
+ *pHdrException = hdr_any;
+ else
+ *pHdrException = hdr_normal;
+
+ return len;
+}
+
+
+static void
+sec_asn1e_write_header (sec_asn1e_state *state)
+{
+ unsigned long contents_length;
+ unsigned char tag_number, tag_modifiers;
+ sec_asn1e_hdr_encoding hdrException = hdr_normal;
+ PRBool indefinite = PR_FALSE;
+
+ PORT_Assert (state->place == beforeHeader);
+
+ tag_number = state->tag_number;
+ tag_modifiers = state->tag_modifiers;
+
+ if (state->underlying_kind == SEC_ASN1_ANY) {
+ state->place = duringContents;
+ return;
+ }
+
+ if (state->underlying_kind & SEC_ASN1_CHOICE) {
+ int indx = sec_asn1e_which_choice(state->src, state->theTemplate);
+ if( 0 == indx ) {
+ /* XXX set an error? "choice not found" */
+ state->top->status = encodeError;
+ return;
+ }
+ state->place = afterChoice;
+ state = sec_asn1e_push_state(state->top, &state->theTemplate[indx],
+ (char *)state->src - state->theTemplate->offset,
+ PR_TRUE);
+ if (state) {
+ /*
+ * Do the "before" field notification.
+ */
+ sec_asn1e_notify_before (state->top, state->src, state->depth);
+ state = sec_asn1e_init_state_based_on_template (state);
+ }
+ return;
+ }
+
+ /* The !isString test below is apparently intended to ensure that all
+ ** constructed types receive indefinite length encoding.
+ */
+ indefinite = (PRBool)
+ (state->top->streaming && state->may_stream &&
+ (state->top->from_buf || !state->is_string));
+
+ /*
+ * If we are doing a definite-length encoding, first we have to
+ * walk the data structure to calculate the entire contents length.
+ * If we are doing an indefinite-length encoding, we still need to
+ * know if the contents is:
+ * optional and to be omitted, or
+ * an ANY (header is pre-encoded), or
+ * a SAVE or some other kind of template used only by the decoder.
+ * So, we call this function either way.
+ */
+ contents_length = sec_asn1e_contents_length (state->theTemplate,
+ state->src,
+ state->disallowStreaming,
+ indefinite,
+ &hdrException);
+ /*
+ * We might be told explicitly not to put out a header.
+ * But it can also be the case, via a pushed subtemplate, that
+ * sec_asn1e_contents_length could not know that this field is
+ * really optional. So check for that explicitly, too.
+ */
+ if (hdrException != hdr_normal ||
+ (contents_length == 0 && state->optional)) {
+ state->place = afterContents;
+ if (state->top->streaming &&
+ state->may_stream &&
+ state->top->from_buf) {
+ /* we did not find an optional indefinite string, so we
+ * don't encode it. However, if TakeFromBuf is on, we stop
+ * here anyway to give our caller a chance to intercept at the
+ * same point where we would stop if the field were present.
+ */
+ state->top->status = needBytes;
+ }
+ return;
+ }
+
+ if (indefinite) {
+ /*
+ * We need to put out an indefinite-length encoding.
+ * The only universal types that can be constructed are SETs,
+ * SEQUENCEs, and strings; so check that it is one of those,
+ * or that it is not universal (e.g. context-specific).
+ */
+ state->indefinite = PR_TRUE;
+ PORT_Assert ((tag_number == SEC_ASN1_SET)
+ || (tag_number == SEC_ASN1_SEQUENCE)
+ || ((tag_modifiers & SEC_ASN1_CLASS_MASK) != 0)
+ || state->is_string);
+ tag_modifiers |= SEC_ASN1_CONSTRUCTED;
+ contents_length = 0;
+ }
+
+ sec_asn1e_write_identifier_bytes (state,
+ (unsigned char)(tag_number | tag_modifiers));
+ sec_asn1e_write_length_bytes (state, contents_length, state->indefinite);
+
+ if (contents_length == 0 && !state->indefinite) {
+ /*
+ * If no real contents to encode, then we are done with this field.
+ */
+ state->place = afterContents;
+ return;
+ }
+
+ /*
+ * An EXPLICIT is nothing but an outer header, which we have already
+ * written. Now we need to do the inner header and contents.
+ */
+ if (state->isExplicit) {
+ const SEC_ASN1Template *subt =
+ SEC_ASN1GetSubtemplate(state->theTemplate, state->src, PR_TRUE);
+ state->place = afterContents;
+ state = sec_asn1e_push_state (state->top, subt, state->src, PR_TRUE);
+ if (state != NULL)
+ state = sec_asn1e_init_state_based_on_template (state);
+ return;
+ }
+
+ switch (state->underlying_kind) {
+ case SEC_ASN1_SET_OF:
+ case SEC_ASN1_SEQUENCE_OF:
+ /*
+ * We need to push a child to handle each member.
+ */
+ {
+ void **group;
+ const SEC_ASN1Template *subt;
+
+ group = *(void ***)state->src;
+ if (group == NULL || *group == NULL) {
+ /*
+ * Group is empty; we are done.
+ */
+ state->place = afterContents;
+ return;
+ }
+ state->place = duringGroup;
+ subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src,
+ PR_TRUE);
+ state = sec_asn1e_push_state (state->top, subt, *group, PR_TRUE);
+ if (state != NULL)
+ state = sec_asn1e_init_state_based_on_template (state);
+ }
+ break;
+
+ case SEC_ASN1_SEQUENCE:
+ case SEC_ASN1_SET:
+ /*
+ * We need to push a child to handle the individual fields.
+ */
+ state->place = duringSequence;
+ state = sec_asn1e_push_state (state->top, state->theTemplate + 1,
+ state->src, PR_TRUE);
+ if (state != NULL) {
+ /*
+ * Do the "before" field notification.
+ */
+ sec_asn1e_notify_before (state->top, state->src, state->depth);
+ state = sec_asn1e_init_state_based_on_template (state);
+ }
+ break;
+
+ default:
+ /*
+ * I think we do not need to do anything else.
+ * XXX Correct?
+ */
+ state->place = duringContents;
+ break;
+ }
+}
+
+
+static void
+sec_asn1e_write_contents_from_buf (sec_asn1e_state *state,
+ const char *buf, unsigned long len)
+{
+ PORT_Assert (state->place == duringContents);
+ PORT_Assert (state->top->from_buf);
+ PORT_Assert (state->may_stream && !state->disallowStreaming);
+
+ /*
+ * Probably they just turned on "take from buf", but have not
+ * yet given us any bytes. If there is nothing in the buffer
+ * then we have nothing to do but return and wait.
+ */
+ if (buf == NULL || len == 0) {
+ state->top->status = needBytes;
+ return;
+ }
+ /*
+ * We are streaming, reading from a passed-in buffer.
+ * This means we are encoding a simple string or an ANY.
+ * For the former, we need to put out a substring, with its
+ * own identifier and length. For an ANY, we just write it
+ * out as is (our caller is required to ensure that it
+ * is a properly encoded entity).
+ */
+ PORT_Assert (state->is_string); /* includes ANY */
+ if (state->underlying_kind != SEC_ASN1_ANY) {
+ unsigned char identifier;
+
+ /*
+ * Create the identifier based on underlying_kind. We cannot
+ * use tag_number and tag_modifiers because this can be an
+ * implicitly encoded field. In that case, the underlying
+ * substrings *are* encoded with their real tag.
+ */
+ identifier = (unsigned char)
+ (state->underlying_kind & SEC_ASN1_TAG_MASK);
+ /*
+ * The underlying kind should just be a simple string; there
+ * should be no bits like CONTEXT_SPECIFIC or CONSTRUCTED set.
+ */
+ PORT_Assert ((identifier & SEC_ASN1_TAGNUM_MASK) == identifier);
+ /*
+ * Write out the tag and length for the substring.
+ */
+ sec_asn1e_write_identifier_bytes (state, identifier);
+ if (state->underlying_kind == SEC_ASN1_BIT_STRING) {
+ char byte;
+ /*
+ * Assume we have a length in bytes but we need to output
+ * a proper bit string. This interface only works for bit
+ * strings that are full multiples of 8. If support for
+ * real, variable length bit strings is needed then the
+ * caller will have to know to pass in a bit length instead
+ * of a byte length and then this code will have to
+ * perform the encoding necessary (length written is length
+ * in bytes plus 1, and the first octet of string is the
+ * number of bits remaining between the end of the bit
+ * string and the next byte boundary).
+ */
+ sec_asn1e_write_length_bytes (state, len + 1, PR_FALSE);
+ byte = 0;
+ sec_asn1e_write_contents_bytes (state, &byte, 1);
+ } else {
+ sec_asn1e_write_length_bytes (state, len, PR_FALSE);
+ }
+ }
+ sec_asn1e_write_contents_bytes (state, buf, len);
+ state->top->status = needBytes;
+}
+
+static void
+sec_asn1e_write_contents (sec_asn1e_state *state)
+{
+ unsigned long len = 0;
+
+ PORT_Assert (state->place == duringContents);
+
+ switch (state->underlying_kind) {
+ case SEC_ASN1_SET:
+ case SEC_ASN1_SEQUENCE:
+ PORT_Assert (0);
+ break;
+
+ case SEC_ASN1_BIT_STRING:
+ {
+ SECItem *item;
+ char rem;
+
+ item = (SECItem *)state->src;
+ len = (item->len + 7) >> 3;
+ rem = (unsigned char)((len << 3) - item->len); /* remaining bits */
+ sec_asn1e_write_contents_bytes (state, &rem, 1);
+ sec_asn1e_write_contents_bytes (state, (char *) item->data, len);
+ }
+ break;
+
+ case SEC_ASN1_BMP_STRING:
+ /* The number of bytes must be divisable by 2 */
+ if ((((SECItem *)state->src)->len) % 2) {
+ SEC_ASN1EncoderContext *cx;
+
+ cx = state->top;
+ cx->status = encodeError;
+ break;
+ }
+ /* otherwise, fall through to write the content */
+ goto process_string;
+
+ case SEC_ASN1_UNIVERSAL_STRING:
+ /* The number of bytes must be divisable by 4 */
+ if ((((SECItem *)state->src)->len) % 4) {
+ SEC_ASN1EncoderContext *cx;
+
+ cx = state->top;
+ cx->status = encodeError;
+ break;
+ }
+ /* otherwise, fall through to write the content */
+ goto process_string;
+
+ case SEC_ASN1_INTEGER:
+ /* ASN.1 INTEGERs are signed. If the source is an unsigned
+ * integer, the encoder will need to handle the conversion here.
+ */
+ {
+ unsigned int blen;
+ unsigned char *buf;
+ SECItemType integerType;
+ blen = ((SECItem *)state->src)->len;
+ buf = ((SECItem *)state->src)->data;
+ integerType = ((SECItem *)state->src)->type;
+ while (blen > 0) {
+ if (*buf & 0x80 && integerType == siUnsignedInteger) {
+ char zero = 0; /* write a leading 0 */
+ sec_asn1e_write_contents_bytes(state, &zero, 1);
+ /* and then the remaining buffer */
+ sec_asn1e_write_contents_bytes(state,
+ (char *)buf, blen);
+ break;
+ }
+ /* Check three possibilities:
+ * 1. No leading zeros, msb of MSB is not 1;
+ * 2. The number is zero itself;
+ * 3. Encoding a signed integer with a leading zero,
+ * keep the zero so that the number is positive.
+ */
+ if (*buf != 0 ||
+ blen == 1 ||
+ (buf[1] & 0x80 && integerType != siUnsignedInteger) )
+ {
+ sec_asn1e_write_contents_bytes(state,
+ (char *)buf, blen);
+ break;
+ }
+ /* byte is 0, continue */
+ buf++;
+ blen--;
+ }
+ }
+ /* done with this content */
+ break;
+
+process_string:
+ default:
+ {
+ SECItem *item;
+
+ item = (SECItem *)state->src;
+ sec_asn1e_write_contents_bytes (state, (char *) item->data,
+ item->len);
+ }
+ break;
+ }
+ state->place = afterContents;
+}
+
+/*
+ * We are doing a SET OF or SEQUENCE OF, and have just finished an item.
+ */
+static void
+sec_asn1e_next_in_group (sec_asn1e_state *state)
+{
+ sec_asn1e_state *child;
+ void **group;
+ void *member;
+
+ PORT_Assert (state->place == duringGroup);
+ PORT_Assert (state->child != NULL);
+
+ child = state->child;
+
+ group = *(void ***)state->src;
+
+ /*
+ * Find placement of current item.
+ */
+ member = (char *)(state->child->src) - child->theTemplate->offset;
+ while (*group != member)
+ group++;
+
+ /*
+ * Move forward to next item.
+ */
+ group++;
+ if (*group == NULL) {
+ /*
+ * That was our last one; we are done now.
+ */
+ child->place = notInUse;
+ state->place = afterContents;
+ return;
+ }
+ child->src = (char *)(*group) + child->theTemplate->offset;
+
+ /*
+ * Re-"push" child.
+ */
+ sec_asn1e_scrub_state (child);
+ state->top->current = child;
+}
+
+
+/*
+ * We are moving along through a sequence; move forward by one,
+ * (detecting end-of-sequence when it happens).
+ */
+static void
+sec_asn1e_next_in_sequence (sec_asn1e_state *state)
+{
+ sec_asn1e_state *child;
+
+ PORT_Assert (state->place == duringSequence);
+ PORT_Assert (state->child != NULL);
+
+ child = state->child;
+
+ /*
+ * Do the "after" field notification.
+ */
+ sec_asn1e_notify_after (state->top, child->src, child->depth);
+
+ /*
+ * Move forward.
+ */
+ child->theTemplate++;
+ if (child->theTemplate->kind == 0) {
+ /*
+ * We are done with this sequence.
+ */
+ child->place = notInUse;
+ state->place = afterContents;
+ return;
+ }
+
+ /*
+ * Reset state and push.
+ */
+
+ child->src = (char *)state->src + child->theTemplate->offset;
+
+ /*
+ * Do the "before" field notification.
+ */
+ sec_asn1e_notify_before (state->top, child->src, child->depth);
+
+ state->top->current = child;
+ (void) sec_asn1e_init_state_based_on_template (child);
+}
+
+
+static void
+sec_asn1e_after_contents (sec_asn1e_state *state)
+{
+ PORT_Assert (state->place == afterContents);
+
+ if (state->indefinite)
+ sec_asn1e_write_end_of_contents_bytes (state);
+
+ /*
+ * Just make my parent be the current state. It will then clean
+ * up after me and free me (or reuse me).
+ */
+ state->top->current = state->parent;
+}
+
+
+/*
+ * This function is called whether or not we are streaming; if we
+ * *are* streaming, our caller can also instruct us to take bytes
+ * from the passed-in buffer (at buf, for length len, which is likely
+ * bytes but could even mean bits if the current field is a bit string).
+ * If we have been so instructed, we will gobble up bytes from there
+ * (rather than from our src structure) and output them, and then
+ * we will just return, expecting to be called again -- either with
+ * more bytes or after our caller has instructed us that we are done
+ * (for now) with the buffer.
+ */
+SECStatus
+SEC_ASN1EncoderUpdate (SEC_ASN1EncoderContext *cx,
+ const char *buf, unsigned long len)
+{
+ sec_asn1e_state *state;
+
+ if (cx->status == needBytes) {
+ cx->status = keepGoing;
+ }
+
+ while (cx->status == keepGoing) {
+ state = cx->current;
+ switch (state->place) {
+ case beforeHeader:
+ sec_asn1e_write_header (state);
+ break;
+ case duringContents:
+ if (cx->from_buf)
+ sec_asn1e_write_contents_from_buf (state, buf, len);
+ else
+ sec_asn1e_write_contents (state);
+ break;
+ case duringGroup:
+ sec_asn1e_next_in_group (state);
+ break;
+ case duringSequence:
+ sec_asn1e_next_in_sequence (state);
+ break;
+ case afterContents:
+ sec_asn1e_after_contents (state);
+ break;
+ case afterImplicit:
+ case afterInline:
+ case afterPointer:
+ case afterChoice:
+ /*
+ * These states are more documentation than anything.
+ * They just need to force a pop.
+ */
+ PORT_Assert (!state->indefinite);
+ state->place = afterContents;
+ break;
+ case notInUse:
+ default:
+ /* This is not an error, but rather a plain old BUG! */
+ PORT_Assert (0);
+ cx->status = encodeError;
+ break;
+ }
+
+ if (cx->status == encodeError)
+ break;
+
+ /* It might have changed, so we have to update our local copy. */
+ state = cx->current;
+
+ /* If it is NULL, we have popped all the way to the top. */
+ if (state == NULL) {
+ cx->status = allDone;
+ break;
+ }
+ }
+
+ if (cx->status == encodeError) {
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+
+void
+SEC_ASN1EncoderFinish (SEC_ASN1EncoderContext *cx)
+{
+ /*
+ * XXX anything else that needs to be finished?
+ */
+
+ PORT_FreeArena (cx->our_pool, PR_FALSE);
+}
+
+
+SEC_ASN1EncoderContext *
+SEC_ASN1EncoderStart (const void *src, const SEC_ASN1Template *theTemplate,
+ SEC_ASN1WriteProc output_proc, void *output_arg)
+{
+ PRArenaPool *our_pool;
+ SEC_ASN1EncoderContext *cx;
+
+ our_pool = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if (our_pool == NULL)
+ return NULL;
+
+ cx = (SEC_ASN1EncoderContext*)PORT_ArenaZAlloc (our_pool, sizeof(*cx));
+ if (cx == NULL) {
+ PORT_FreeArena (our_pool, PR_FALSE);
+ return NULL;
+ }
+
+ cx->our_pool = our_pool;
+ cx->output_proc = output_proc;
+ cx->output_arg = output_arg;
+
+ cx->status = keepGoing;
+
+ if (sec_asn1e_push_state(cx, theTemplate, src, PR_FALSE) == NULL
+ || sec_asn1e_init_state_based_on_template (cx->current) == NULL) {
+ /*
+ * Trouble initializing (probably due to failed allocations)
+ * requires that we just give up.
+ */
+ PORT_FreeArena (our_pool, PR_FALSE);
+ return NULL;
+ }
+
+ return cx;
+}
+
+
+/*
+ * XXX Do we need a FilterProc, too?
+ */
+
+
+void
+SEC_ASN1EncoderSetNotifyProc (SEC_ASN1EncoderContext *cx,
+ SEC_ASN1NotifyProc fn, void *arg)
+{
+ cx->notify_proc = fn;
+ cx->notify_arg = arg;
+}
+
+
+void
+SEC_ASN1EncoderClearNotifyProc (SEC_ASN1EncoderContext *cx)
+{
+ cx->notify_proc = NULL;
+ cx->notify_arg = NULL; /* not necessary; just being clean */
+}
+
+void
+SEC_ASN1EncoderAbort(SEC_ASN1EncoderContext *cx, int error)
+{
+ PORT_Assert(cx);
+ PORT_SetError(error);
+ cx->status = encodeError;
+}
+
+void
+SEC_ASN1EncoderSetStreaming (SEC_ASN1EncoderContext *cx)
+{
+ /* XXX is there a way to check that we are "between" fields here? */
+
+ cx->streaming = PR_TRUE;
+}
+
+
+void
+SEC_ASN1EncoderClearStreaming (SEC_ASN1EncoderContext *cx)
+{
+ /* XXX is there a way to check that we are "between" fields here? */
+
+ cx->streaming = PR_FALSE;
+}
+
+
+void
+SEC_ASN1EncoderSetTakeFromBuf (SEC_ASN1EncoderContext *cx)
+{
+ /*
+ * XXX is there a way to check that we are "between" fields here? this
+ * needs to include a check for being in between groups of items in
+ * a SET_OF or SEQUENCE_OF.
+ */
+ PORT_Assert (cx->streaming);
+
+ cx->from_buf = PR_TRUE;
+}
+
+
+void
+SEC_ASN1EncoderClearTakeFromBuf (SEC_ASN1EncoderContext *cx)
+{
+ /* we should actually be taking from buf *now* */
+ PORT_Assert (cx->from_buf);
+ if (! cx->from_buf) /* if not, just do nothing */
+ return;
+
+ cx->from_buf = PR_FALSE;
+
+ if (cx->status == needBytes) {
+ cx->status = keepGoing;
+ cx->current->place = afterContents;
+ }
+}
+
+
+SECStatus
+SEC_ASN1Encode (const void *src, const SEC_ASN1Template *theTemplate,
+ SEC_ASN1WriteProc output_proc, void *output_arg)
+{
+ SEC_ASN1EncoderContext *ecx;
+ SECStatus rv;
+
+ ecx = SEC_ASN1EncoderStart (src, theTemplate, output_proc, output_arg);
+ if (ecx == NULL)
+ return SECFailure;
+
+ rv = SEC_ASN1EncoderUpdate (ecx, NULL, 0);
+
+ SEC_ASN1EncoderFinish (ecx);
+ return rv;
+}
+
+
+/*
+ * XXX depth and data_kind are unused; is there a PC way to silence warnings?
+ * (I mean "politically correct", not anything to do with intel/win platform)
+ */
+static void
+sec_asn1e_encode_item_count (void *arg, const char *buf, unsigned long len,
+ int depth, SEC_ASN1EncodingPart data_kind)
+{
+ unsigned long *count;
+
+ count = (unsigned long*)arg;
+ PORT_Assert (count != NULL);
+
+ *count += len;
+}
+
+
+/* XXX depth and data_kind are unused; is there a PC way to silence warnings? */
+static void
+sec_asn1e_encode_item_store (void *arg, const char *buf, unsigned long len,
+ int depth, SEC_ASN1EncodingPart data_kind)
+{
+ SECItem *dest;
+
+ dest = (SECItem*)arg;
+ PORT_Assert (dest != NULL);
+
+ PORT_Memcpy (dest->data + dest->len, buf, len);
+ dest->len += len;
+}
+
+
+/*
+ * Allocate an entire SECItem, or just the data part of it, to hold
+ * "len" bytes of stuff. Allocate from the given pool, if specified,
+ * otherwise just do a vanilla PORT_Alloc.
+ *
+ * XXX This seems like a reasonable general-purpose function (for SECITEM_)?
+ */
+static SECItem *
+sec_asn1e_allocate_item (PRArenaPool *poolp, SECItem *dest, unsigned long len)
+{
+ if (poolp != NULL) {
+ void *release;
+
+ release = PORT_ArenaMark (poolp);
+ if (dest == NULL)
+ dest = (SECItem*)PORT_ArenaAlloc (poolp, sizeof(SECItem));
+ if (dest != NULL) {
+ dest->data = (unsigned char*)PORT_ArenaAlloc (poolp, len);
+ if (dest->data == NULL) {
+ dest = NULL;
+ }
+ }
+ if (dest == NULL) {
+ /* one or both allocations failed; release everything */
+ PORT_ArenaRelease (poolp, release);
+ } else {
+ /* everything okay; unmark the arena */
+ PORT_ArenaUnmark (poolp, release);
+ }
+ } else {
+ SECItem *indest;
+
+ indest = dest;
+ if (dest == NULL)
+ dest = (SECItem*)PORT_Alloc (sizeof(SECItem));
+ if (dest != NULL) {
+ dest->type = siBuffer;
+ dest->data = (unsigned char*)PORT_Alloc (len);
+ if (dest->data == NULL) {
+ if (indest == NULL)
+ PORT_Free (dest);
+ dest = NULL;
+ }
+ }
+ }
+
+ return dest;
+}
+
+
+SECItem *
+SEC_ASN1EncodeItem (PRArenaPool *poolp, SECItem *dest, const void *src,
+ const SEC_ASN1Template *theTemplate)
+{
+ unsigned long encoding_length;
+ SECStatus rv;
+
+ PORT_Assert (dest == NULL || dest->data == NULL);
+
+ encoding_length = 0;
+ rv = SEC_ASN1Encode (src, theTemplate,
+ sec_asn1e_encode_item_count, &encoding_length);
+ if (rv != SECSuccess)
+ return NULL;
+
+ dest = sec_asn1e_allocate_item (poolp, dest, encoding_length);
+ if (dest == NULL)
+ return NULL;
+
+ /* XXX necessary? This really just checks for a bug in the allocate fn */
+ PORT_Assert (dest->data != NULL);
+ if (dest->data == NULL)
+ return NULL;
+
+ dest->len = 0;
+ (void) SEC_ASN1Encode (src, theTemplate, sec_asn1e_encode_item_store, dest);
+
+ PORT_Assert (encoding_length == dest->len);
+ return dest;
+}
+
+
+static SECItem *
+sec_asn1e_integer(PRArenaPool *poolp, SECItem *dest, unsigned long value,
+ PRBool make_unsigned)
+{
+ unsigned long copy;
+ unsigned char sign;
+ int len = 0;
+
+ /*
+ * Determine the length of the encoded value (minimum of 1).
+ */
+ copy = value;
+ do {
+ len++;
+ sign = (unsigned char)(copy & 0x80);
+ copy >>= 8;
+ } while (copy);
+
+ /*
+ * If this is an unsigned encoding, and the high bit of the last
+ * byte we counted was set, we need to add one to the length so
+ * we put a high-order zero byte in the encoding.
+ */
+ if (sign && make_unsigned)
+ len++;
+
+ /*
+ * Allocate the item (if necessary) and the data pointer within.
+ */
+ dest = sec_asn1e_allocate_item (poolp, dest, len);
+ if (dest == NULL)
+ return NULL;
+
+ /*
+ * Store the value, byte by byte, in the item.
+ */
+ dest->len = len;
+ while (len) {
+ dest->data[--len] = (unsigned char)value;
+ value >>= 8;
+ }
+ PORT_Assert (value == 0);
+
+ return dest;
+}
+
+
+SECItem *
+SEC_ASN1EncodeInteger(PRArenaPool *poolp, SECItem *dest, long value)
+{
+ return sec_asn1e_integer (poolp, dest, (unsigned long) value, PR_FALSE);
+}
+
+
+SECItem *
+SEC_ASN1EncodeUnsignedInteger(PRArenaPool *poolp,
+ SECItem *dest, unsigned long value)
+{
+ return sec_asn1e_integer (poolp, dest, value, PR_TRUE);
+}
diff --git a/security/nss/lib/util/secasn1t.h b/security/nss/lib/util/secasn1t.h
new file mode 100644
index 000000000..3b3036f30
--- /dev/null
+++ b/security/nss/lib/util/secasn1t.h
@@ -0,0 +1,302 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Types for encoding/decoding of ASN.1 using BER/DER (Basic/Distinguished
+ * Encoding Rules).
+ *
+ * $Id$
+ */
+
+#ifndef _SECASN1T_H_
+#define _SECASN1T_H_
+
+#include "utilrename.h"
+
+/*
+** An array of these structures defines a BER/DER encoding for an object.
+**
+** The array usually starts with a dummy entry whose kind is SEC_ASN1_SEQUENCE;
+** such an array is terminated with an entry where kind == 0. (An array
+** which consists of a single component does not require a second dummy
+** entry -- the array is only searched as long as previous component(s)
+** instruct it.)
+*/
+typedef struct sec_ASN1Template_struct {
+ /*
+ ** Kind of item being decoded/encoded, including tags and modifiers.
+ */
+ unsigned long kind;
+
+ /*
+ ** The value is the offset from the base of the structure to the
+ ** field that holds the value being decoded/encoded.
+ */
+ unsigned long offset;
+
+ /*
+ ** When kind suggests it (SEC_ASN1_POINTER, SEC_ASN1_GROUP, SEC_ASN1_INLINE,
+ ** or a component that is *not* a SEC_ASN1_UNIVERSAL), this points to
+ ** a sub-template for nested encoding/decoding,
+ ** OR, iff SEC_ASN1_DYNAMIC is set, then this is a pointer to a pointer
+ ** to a function which will return the appropriate template when called
+ ** at runtime. NOTE! that explicit level of indirection, which is
+ ** necessary because ANSI does not allow you to store a function
+ ** pointer directly as a "void *" so we must store it separately and
+ ** dereference it to get at the function pointer itself.
+ */
+ const void *sub;
+
+ /*
+ ** In the first element of a template array, the value is the size
+ ** of the structure to allocate when this template is being referenced
+ ** by another template via SEC_ASN1_POINTER or SEC_ASN1_GROUP.
+ ** In all other cases, the value is ignored.
+ */
+ unsigned int size;
+} SEC_ASN1Template;
+
+
+/* default size used for allocation of encoding/decoding stuff */
+/* XXX what is the best value here? */
+#define SEC_ASN1_DEFAULT_ARENA_SIZE (2048)
+
+/*
+** BER/DER values for ASN.1 identifier octets.
+*/
+#define SEC_ASN1_TAG_MASK 0xff
+
+/*
+ * BER/DER universal type tag numbers.
+ * The values are defined by the X.208 standard; do not change them!
+ * NOTE: if you add anything to this list, you must add code to secasn1d.c
+ * to accept the tag, and probably also to secasn1e.c to encode it.
+ * XXX It appears some have been added recently without being added to
+ * the code; so need to go through the list now and double-check them all.
+ * (Look especially at those added in revision 1.10.)
+ */
+#define SEC_ASN1_TAGNUM_MASK 0x1f
+#define SEC_ASN1_BOOLEAN 0x01
+#define SEC_ASN1_INTEGER 0x02
+#define SEC_ASN1_BIT_STRING 0x03
+#define SEC_ASN1_OCTET_STRING 0x04
+#define SEC_ASN1_NULL 0x05
+#define SEC_ASN1_OBJECT_ID 0x06
+#define SEC_ASN1_OBJECT_DESCRIPTOR 0x07
+/* External type and instance-of type 0x08 */
+#define SEC_ASN1_REAL 0x09
+#define SEC_ASN1_ENUMERATED 0x0a
+#define SEC_ASN1_EMBEDDED_PDV 0x0b
+#define SEC_ASN1_UTF8_STRING 0x0c
+/* 0x0d */
+/* 0x0e */
+/* 0x0f */
+#define SEC_ASN1_SEQUENCE 0x10
+#define SEC_ASN1_SET 0x11
+#define SEC_ASN1_NUMERIC_STRING 0x12
+#define SEC_ASN1_PRINTABLE_STRING 0x13
+#define SEC_ASN1_T61_STRING 0x14
+#define SEC_ASN1_VIDEOTEX_STRING 0x15
+#define SEC_ASN1_IA5_STRING 0x16
+#define SEC_ASN1_UTC_TIME 0x17
+#define SEC_ASN1_GENERALIZED_TIME 0x18
+#define SEC_ASN1_GRAPHIC_STRING 0x19
+#define SEC_ASN1_VISIBLE_STRING 0x1a
+#define SEC_ASN1_GENERAL_STRING 0x1b
+#define SEC_ASN1_UNIVERSAL_STRING 0x1c
+/* 0x1d */
+#define SEC_ASN1_BMP_STRING 0x1e
+#define SEC_ASN1_HIGH_TAG_NUMBER 0x1f
+#define SEC_ASN1_TELETEX_STRING SEC_ASN1_T61_STRING
+
+/*
+** Modifiers to type tags. These are also specified by a/the
+** standard, and must not be changed.
+*/
+
+#define SEC_ASN1_METHOD_MASK 0x20
+#define SEC_ASN1_PRIMITIVE 0x00
+#define SEC_ASN1_CONSTRUCTED 0x20
+
+#define SEC_ASN1_CLASS_MASK 0xc0
+#define SEC_ASN1_UNIVERSAL 0x00
+#define SEC_ASN1_APPLICATION 0x40
+#define SEC_ASN1_CONTEXT_SPECIFIC 0x80
+#define SEC_ASN1_PRIVATE 0xc0
+
+/*
+** Our additions, used for templates.
+** These are not defined by any standard; the values are used internally only.
+** Just be careful to keep them out of the low 8 bits.
+** XXX finish comments
+*/
+#define SEC_ASN1_OPTIONAL 0x00100
+#define SEC_ASN1_EXPLICIT 0x00200
+#define SEC_ASN1_ANY 0x00400
+#define SEC_ASN1_INLINE 0x00800
+#define SEC_ASN1_POINTER 0x01000
+#define SEC_ASN1_GROUP 0x02000 /* with SET or SEQUENCE means
+ * SET OF or SEQUENCE OF */
+#define SEC_ASN1_DYNAMIC 0x04000 /* subtemplate is found by calling
+ * a function at runtime */
+#define SEC_ASN1_SKIP 0x08000 /* skip a field; only for decoding */
+#define SEC_ASN1_INNER 0x10000 /* with ANY means capture the
+ * contents only (not the id, len,
+ * or eoc); only for decoding */
+#define SEC_ASN1_SAVE 0x20000 /* stash away the encoded bytes first;
+ * only for decoding */
+#define SEC_ASN1_MAY_STREAM 0x40000 /* field or one of its sub-fields may
+ * stream in and so should encode as
+ * indefinite-length when streaming
+ * has been indicated; only for
+ * encoding */
+#define SEC_ASN1_SKIP_REST 0x80000 /* skip all following fields;
+ only for decoding */
+#define SEC_ASN1_CHOICE 0x100000 /* pick one from a template */
+#define SEC_ASN1_NO_STREAM 0X200000 /* This entry will not stream
+ even if the sub-template says
+ streaming is possible. Helps
+ to solve ambiguities with potential
+ streaming entries that are
+ optional */
+#define SEC_ASN1_DEBUG_BREAK 0X400000 /* put this in your template and the
+ decoder will assert when it
+ processes it. Only for use with
+ SEC_QuickDERDecodeItem */
+
+
+
+/* Shorthand/Aliases */
+#define SEC_ASN1_SEQUENCE_OF (SEC_ASN1_GROUP | SEC_ASN1_SEQUENCE)
+#define SEC_ASN1_SET_OF (SEC_ASN1_GROUP | SEC_ASN1_SET)
+#define SEC_ASN1_ANY_CONTENTS (SEC_ASN1_ANY | SEC_ASN1_INNER)
+
+/* Maximum depth of nested SEQUENCEs and SETs */
+#define SEC_ASN1D_MAX_DEPTH 32
+
+/*
+** Function used for SEC_ASN1_DYNAMIC.
+** "arg" is a pointer to the structure being encoded/decoded
+** "enc", when true, means that we are encoding (false means decoding)
+*/
+typedef const SEC_ASN1Template * SEC_ASN1TemplateChooser(void *arg, PRBool enc);
+typedef SEC_ASN1TemplateChooser * SEC_ASN1TemplateChooserPtr;
+
+#if defined(_WIN32)
+#define SEC_ASN1_GET(x) NSS_Get_##x(NULL, PR_FALSE)
+#define SEC_ASN1_SUB(x) &p_NSS_Get_##x
+#define SEC_ASN1_XTRN SEC_ASN1_DYNAMIC
+#define SEC_ASN1_MKSUB(x) \
+static const SEC_ASN1TemplateChooserPtr p_NSS_Get_##x = &NSS_Get_##x;
+#else
+#define SEC_ASN1_GET(x) x
+#define SEC_ASN1_SUB(x) x
+#define SEC_ASN1_XTRN 0
+#define SEC_ASN1_MKSUB(x)
+#endif
+
+#define SEC_ASN1_CHOOSER_DECLARE(x) \
+extern const SEC_ASN1Template * NSS_Get_##x (void *arg, PRBool enc);
+
+#define SEC_ASN1_CHOOSER_IMPLEMENT(x) \
+const SEC_ASN1Template * NSS_Get_##x(void * arg, PRBool enc) \
+{ return x; }
+
+/*
+** Opaque object used by the decoder to store state.
+*/
+typedef struct sec_DecoderContext_struct SEC_ASN1DecoderContext;
+
+/*
+** Opaque object used by the encoder to store state.
+*/
+typedef struct sec_EncoderContext_struct SEC_ASN1EncoderContext;
+
+/*
+ * This is used to describe to a filter function the bytes that are
+ * being passed to it. This is only useful when the filter is an "outer"
+ * one, meaning it expects to get *all* of the bytes not just the
+ * contents octets.
+ */
+typedef enum {
+ SEC_ASN1_Identifier = 0,
+ SEC_ASN1_Length = 1,
+ SEC_ASN1_Contents = 2,
+ SEC_ASN1_EndOfContents = 3
+} SEC_ASN1EncodingPart;
+
+/*
+ * Type of the function pointer used either for decoding or encoding,
+ * when doing anything "funny" (e.g. manipulating the data stream)
+ */
+typedef void (* SEC_ASN1NotifyProc)(void *arg, PRBool before,
+ void *dest, int real_depth);
+
+/*
+ * Type of the function pointer used for grabbing encoded bytes.
+ * This can be used during either encoding or decoding, as follows...
+ *
+ * When decoding, this can be used to filter the encoded bytes as they
+ * are parsed. This is what you would do if you wanted to process the data
+ * along the way (like to decrypt it, or to perform a hash on it in order
+ * to do a signature check later). See SEC_ASN1DecoderSetFilterProc().
+ * When processing only part of the encoded bytes is desired, you "watch"
+ * for the field(s) you are interested in with a "notify proc" (see
+ * SEC_ASN1DecoderSetNotifyProc()) and for even finer granularity (e.g. to
+ * ignore all by the contents bytes) you pay attention to the "data_kind"
+ * parameter.
+ *
+ * When encoding, this is the specification for the output function which
+ * will receive the bytes as they are encoded. The output function can
+ * perform any postprocessing necessary (like hashing (some of) the data
+ * to create a digest that gets included at the end) as well as shoving
+ * the data off wherever it needs to go. (In order to "tune" any processing,
+ * you can set a "notify proc" as described above in the decoding case.)
+ *
+ * The parameters:
+ * - "arg" is an opaque pointer that you provided at the same time you
+ * specified a function of this type
+ * - "data" is a buffer of length "len", containing the encoded bytes
+ * - "depth" is how deep in a nested encoding we are (it is not usually
+ * valuable, but can be useful sometimes so I included it)
+ * - "data_kind" tells you if these bytes are part of the ASN.1 encoded
+ * octets for identifier, length, contents, or end-of-contents
+ */
+typedef void (* SEC_ASN1WriteProc)(void *arg,
+ const char *data, unsigned long len,
+ int depth, SEC_ASN1EncodingPart data_kind);
+
+#endif /* _SECASN1T_H_ */
diff --git a/security/nss/lib/util/secasn1u.c b/security/nss/lib/util/secasn1u.c
new file mode 100644
index 000000000..1514bd7ed
--- /dev/null
+++ b/security/nss/lib/util/secasn1u.c
@@ -0,0 +1,131 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Utility routines to complement the ASN.1 encoding and decoding functions.
+ *
+ * $Id$
+ */
+
+#include "secasn1.h"
+
+
+/*
+ * We have a length that needs to be encoded; how many bytes will the
+ * encoding take?
+ *
+ * The rules are that 0 - 0x7f takes one byte (the length itself is the
+ * entire encoding); everything else takes one plus the number of bytes
+ * in the length.
+ */
+int
+SEC_ASN1LengthLength (unsigned long len)
+{
+ int lenlen = 1;
+
+ if (len > 0x7f) {
+ do {
+ lenlen++;
+ len >>= 8;
+ } while (len);
+ }
+
+ return lenlen;
+}
+
+
+/*
+ * XXX Move over (and rewrite as appropriate) the rest of the
+ * stuff in dersubr.c!
+ */
+
+
+/*
+ * Find the appropriate subtemplate for the given template.
+ * This may involve calling a "chooser" function, or it may just
+ * be right there. In either case, it is expected to *have* a
+ * subtemplate; this is asserted in debug builds (in non-debug
+ * builds, NULL will be returned).
+ *
+ * "thing" is a pointer to the structure being encoded/decoded
+ * "encoding", when true, means that we are in the process of encoding
+ * (as opposed to in the process of decoding)
+ */
+const SEC_ASN1Template *
+SEC_ASN1GetSubtemplate (const SEC_ASN1Template *theTemplate, void *thing,
+ PRBool encoding)
+{
+ const SEC_ASN1Template *subt = NULL;
+
+ PORT_Assert (theTemplate->sub != NULL);
+ if (theTemplate->sub != NULL) {
+ if (theTemplate->kind & SEC_ASN1_DYNAMIC) {
+ SEC_ASN1TemplateChooserPtr chooserp;
+
+ chooserp = *(SEC_ASN1TemplateChooserPtr *) theTemplate->sub;
+ if (chooserp) {
+ if (thing != NULL)
+ thing = (char *)thing - theTemplate->offset;
+ subt = (* chooserp)(thing, encoding);
+ }
+ } else {
+ subt = (SEC_ASN1Template*)theTemplate->sub;
+ }
+ }
+ return subt;
+}
+
+PRBool SEC_ASN1IsTemplateSimple(const SEC_ASN1Template *theTemplate)
+{
+ if (!theTemplate) {
+ return PR_TRUE; /* it doesn't get any simpler than NULL */
+ }
+ /* only templates made of one primitive type or a choice of primitive
+ types are considered simple */
+ if (! (theTemplate->kind & (~SEC_ASN1_TAGNUM_MASK))) {
+ return PR_TRUE; /* primitive type */
+ }
+ if (!theTemplate->kind & SEC_ASN1_CHOICE) {
+ return PR_FALSE; /* no choice means not simple */
+ }
+ while (++theTemplate && theTemplate->kind) {
+ if (theTemplate->kind & (~SEC_ASN1_TAGNUM_MASK)) {
+ return PR_FALSE; /* complex type */
+ }
+ }
+ return PR_TRUE; /* choice of primitive types */
+}
+
diff --git a/security/nss/lib/util/seccomon.h b/security/nss/lib/util/seccomon.h
new file mode 100644
index 000000000..1ba9a656e
--- /dev/null
+++ b/security/nss/lib/util/seccomon.h
@@ -0,0 +1,119 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * seccomon.h - common data structures for security libraries
+ *
+ * This file should have lowest-common-denominator datastructures
+ * for security libraries. It should not be dependent on any other
+ * headers, and should not require linking with any libraries.
+ *
+ * $Id$
+ */
+
+#ifndef _SECCOMMON_H_
+#define _SECCOMMON_H_
+
+#include "utilrename.h"
+#include "prtypes.h"
+
+
+#ifdef __cplusplus
+# define SEC_BEGIN_PROTOS extern "C" {
+# define SEC_END_PROTOS }
+#else
+# define SEC_BEGIN_PROTOS
+# define SEC_END_PROTOS
+#endif
+
+#include "secport.h"
+
+typedef enum {
+ siBuffer = 0,
+ siClearDataBuffer = 1,
+ siCipherDataBuffer = 2,
+ siDERCertBuffer = 3,
+ siEncodedCertBuffer = 4,
+ siDERNameBuffer = 5,
+ siEncodedNameBuffer = 6,
+ siAsciiNameString = 7,
+ siAsciiString = 8,
+ siDEROID = 9,
+ siUnsignedInteger = 10,
+ siUTCTime = 11,
+ siGeneralizedTime = 12,
+ siVisibleString = 13,
+ siUTF8String = 14,
+ siBMPString = 15
+} SECItemType;
+
+typedef struct SECItemStr SECItem;
+
+struct SECItemStr {
+ SECItemType type;
+ unsigned char *data;
+ unsigned int len;
+};
+
+/*
+** A status code. Status's are used by procedures that return status
+** values. Again the motivation is so that a compiler can generate
+** warnings when return values are wrong. Correct testing of status codes:
+**
+** SECStatus rv;
+** rv = some_function (some_argument);
+** if (rv != SECSuccess)
+** do_an_error_thing();
+**
+*/
+typedef enum _SECStatus {
+ SECWouldBlock = -2,
+ SECFailure = -1,
+ SECSuccess = 0
+} SECStatus;
+
+/*
+** A comparison code. Used for procedures that return comparision
+** values. Again the motivation is so that a compiler can generate
+** warnings when return values are wrong.
+*/
+typedef enum _SECComparison {
+ SECLessThan = -1,
+ SECEqual = 0,
+ SECGreaterThan = 1
+} SECComparison;
+
+#endif /* _SECCOMMON_H_ */
diff --git a/security/nss/lib/util/secder.h b/security/nss/lib/util/secder.h
new file mode 100644
index 000000000..b227227b9
--- /dev/null
+++ b/security/nss/lib/util/secder.h
@@ -0,0 +1,211 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _SECDER_H_
+#define _SECDER_H_
+
+#include "utilrename.h"
+
+/*
+ * secder.h - public data structures and prototypes for the DER encoding and
+ * decoding utilities library
+ *
+ * $Id$
+ */
+
+#if defined(_WIN32_WCE)
+#else
+#include <time.h>
+#endif
+
+#include "plarena.h"
+#include "prlong.h"
+
+#include "seccomon.h"
+#include "secdert.h"
+#include "prtime.h"
+
+SEC_BEGIN_PROTOS
+
+/*
+** Encode a data structure into DER.
+** "dest" will be filled in (and memory allocated) to hold the der
+** encoded structure in "src"
+** "t" is a template structure which defines the shape of the
+** stored data
+** "src" is a pointer to the structure that will be encoded
+*/
+extern SECStatus DER_Encode(PLArenaPool *arena, SECItem *dest, DERTemplate *t,
+ void *src);
+
+extern SECStatus DER_Lengths(SECItem *item, int *header_len_p,
+ PRUint32 *contents_len_p);
+
+/*
+** Lower level der subroutine that stores the standard header into "to".
+** The header is of variable length, based on encodingLen.
+** The return value is the new value of "to" after skipping over the header.
+** "to" is where the header will be stored
+** "code" is the der code to write
+** "encodingLen" is the number of bytes of data that will follow
+** the header
+*/
+extern unsigned char *DER_StoreHeader(unsigned char *to, unsigned int code,
+ PRUint32 encodingLen);
+
+/*
+** Return the number of bytes it will take to hold a der encoded length.
+*/
+extern int DER_LengthLength(PRUint32 len);
+
+/*
+** Store a der encoded *signed* integer (whose value is "src") into "dst".
+** XXX This should really be enhanced to take a long.
+*/
+extern SECStatus DER_SetInteger(PLArenaPool *arena, SECItem *dst, PRInt32 src);
+
+/*
+** Store a der encoded *unsigned* integer (whose value is "src") into "dst".
+** XXX This should really be enhanced to take an unsigned long.
+*/
+extern SECStatus DER_SetUInteger(PLArenaPool *arena, SECItem *dst, PRUint32 src);
+
+/*
+** Decode a der encoded *signed* integer that is stored in "src".
+** If "-1" is returned, then the caller should check the error in
+** XP_GetError() to see if an overflow occurred (SEC_ERROR_BAD_DER).
+*/
+extern long DER_GetInteger(SECItem *src);
+
+/*
+** Decode a der encoded *unsigned* integer that is stored in "src".
+** If the ULONG_MAX is returned, then the caller should check the error
+** in XP_GetError() to see if an overflow occurred (SEC_ERROR_BAD_DER).
+*/
+extern unsigned long DER_GetUInteger(SECItem *src);
+
+/*
+** Convert an NSPR time value to a der encoded time value.
+** "result" is the der encoded time (memory is allocated)
+** "time" is the NSPR time value (Since Jan 1st, 1970).
+** time must be on or after January 1, 1950, and
+** before January 1, 2050
+** The caller is responsible for freeing up the buffer which
+** result->data points to upon a successful operation.
+*/
+extern SECStatus DER_TimeToUTCTime(SECItem *result, PRTime time);
+extern SECStatus DER_TimeToUTCTimeArena(PLArenaPool* arenaOpt,
+ SECItem *dst, PRTime gmttime);
+
+
+/*
+** Convert an ascii encoded time value (according to DER rules) into
+** an NSPR time value.
+** "result" the resulting NSPR time
+** "string" the der notation ascii value to decode
+*/
+extern SECStatus DER_AsciiToTime(PRTime *result, const char *string);
+
+/*
+** Same as DER_AsciiToTime except takes an SECItem instead of a string
+*/
+extern SECStatus DER_UTCTimeToTime(PRTime *result, const SECItem *time);
+
+/*
+** Convert a DER encoded UTC time to an ascii time representation
+** "utctime" is the DER encoded UTC time to be converted. The
+** caller is responsible for deallocating the returned buffer.
+*/
+extern char *DER_UTCTimeToAscii(SECItem *utcTime);
+
+/*
+** Convert a DER encoded UTC time to an ascii time representation, but only
+** include the day, not the time.
+** "utctime" is the DER encoded UTC time to be converted.
+** The caller is responsible for deallocating the returned buffer.
+*/
+extern char *DER_UTCDayToAscii(SECItem *utctime);
+/* same thing for DER encoded GeneralizedTime */
+extern char *DER_GeneralizedDayToAscii(SECItem *gentime);
+/* same thing for either DER UTCTime or GeneralizedTime */
+extern char *DER_TimeChoiceDayToAscii(SECItem *timechoice);
+
+/*
+** Convert a PRTime time to a DER encoded Generalized time
+** gmttime must be on or after January 1, year 1 and
+** before January 1, 10000.
+*/
+extern SECStatus DER_TimeToGeneralizedTime(SECItem *dst, PRTime gmttime);
+extern SECStatus DER_TimeToGeneralizedTimeArena(PLArenaPool* arenaOpt,
+ SECItem *dst, PRTime gmttime);
+
+/*
+** Convert a DER encoded Generalized time value into an NSPR time value.
+** "dst" the resulting NSPR time
+** "string" the der notation ascii value to decode
+*/
+extern SECStatus DER_GeneralizedTimeToTime(PRTime *dst, const SECItem *time);
+
+/*
+** Convert from a PRTime UTC time value to a formatted ascii value. The
+** caller is responsible for deallocating the returned buffer.
+*/
+extern char *CERT_UTCTime2FormattedAscii (PRTime utcTime, char *format);
+#define CERT_GeneralizedTime2FormattedAscii CERT_UTCTime2FormattedAscii
+
+/*
+** Convert from a PRTime Generalized time value to a formatted ascii value. The
+** caller is responsible for deallocating the returned buffer.
+*/
+extern char *CERT_GenTime2FormattedAscii (PRTime genTime, char *format);
+
+/*
+** decode a SECItem containing either a SEC_ASN1_GENERALIZED_TIME
+** or a SEC_ASN1_UTC_TIME
+*/
+
+extern SECStatus DER_DecodeTimeChoice(PRTime* output, const SECItem* input);
+
+/* encode a PRTime to an ASN.1 DER SECItem containing either a
+ SEC_ASN1_GENERALIZED_TIME or a SEC_ASN1_UTC_TIME */
+
+extern SECStatus DER_EncodeTimeChoice(PLArenaPool* arena, SECItem* output,
+ PRTime input);
+
+SEC_END_PROTOS
+
+#endif /* _SECDER_H_ */
+
diff --git a/security/nss/lib/util/secdert.h b/security/nss/lib/util/secdert.h
new file mode 100644
index 000000000..d7aba05ee
--- /dev/null
+++ b/security/nss/lib/util/secdert.h
@@ -0,0 +1,163 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _SECDERT_H_
+#define _SECDERT_H_
+/*
+ * secdert.h - public data structures for the DER encoding and
+ * decoding utilities library
+ *
+ * $Id$
+ */
+
+#include "utilrename.h"
+#include "seccomon.h"
+
+typedef struct DERTemplateStr DERTemplate;
+
+/*
+** An array of these structures defines an encoding for an object using DER.
+** The array usually starts with a dummy entry whose kind is DER_SEQUENCE;
+** such an array is terminated with an entry where kind == 0. (An array
+** which consists of a single component does not require a second dummy
+** entry -- the array is only searched as long as previous component(s)
+** instruct it.)
+*/
+struct DERTemplateStr {
+ /*
+ ** Kind of item being decoded/encoded, including tags and modifiers.
+ */
+ unsigned long kind;
+
+ /*
+ ** Offset from base of structure to field that holds the value
+ ** being decoded/encoded.
+ */
+ unsigned int offset;
+
+ /*
+ ** When kind suggests it (DER_POINTER, DER_INDEFINITE, DER_INLINE),
+ ** this points to a sub-template for nested encoding/decoding.
+ */
+ DERTemplate *sub;
+
+ /*
+ ** Argument value, dependent on "kind" and/or template placement
+ ** within an array of templates:
+ ** - In the first element of a template array, the value is the
+ ** size of the structure to allocate when this template is being
+ ** referenced by another template via DER_POINTER or DER_INDEFINITE.
+ ** - In a component of a DER_SET or DER_SEQUENCE which is *not* a
+ ** DER_UNIVERSAL type (that is, it has a class tag for either
+ ** DER_APPLICATION, DER_CONTEXT_SPECIFIC, or DER_PRIVATE), the
+ ** value is the underlying type of item being decoded/encoded.
+ */
+ unsigned long arg;
+};
+
+/************************************************************************/
+
+/* default chunksize for arenas used for DER stuff */
+#define DER_DEFAULT_CHUNKSIZE (2048)
+
+/*
+** BER/DER values for ASN.1 identifier octets.
+*/
+#define DER_TAG_MASK 0xff
+
+/*
+ * BER/DER universal type tag numbers.
+ * The values are defined by the X.208 standard; do not change them!
+ * NOTE: if you add anything to this list, you must add code to derdec.c
+ * to accept the tag, and probably also to derenc.c to encode it.
+ */
+#define DER_TAGNUM_MASK 0x1f
+#define DER_BOOLEAN 0x01
+#define DER_INTEGER 0x02
+#define DER_BIT_STRING 0x03
+#define DER_OCTET_STRING 0x04
+#define DER_NULL 0x05
+#define DER_OBJECT_ID 0x06
+#define DER_SEQUENCE 0x10
+#define DER_SET 0x11
+#define DER_PRINTABLE_STRING 0x13
+#define DER_T61_STRING 0x14
+#define DER_IA5_STRING 0x16
+#define DER_UTC_TIME 0x17
+#define DER_VISIBLE_STRING 0x1a
+#define DER_HIGH_TAG_NUMBER 0x1f
+
+/*
+** Modifiers to type tags. These are also specified by a/the
+** standard, and must not be changed.
+*/
+
+#define DER_METHOD_MASK 0x20
+#define DER_PRIMITIVE 0x00
+#define DER_CONSTRUCTED 0x20
+
+#define DER_CLASS_MASK 0xc0
+#define DER_UNIVERSAL 0x00
+#define DER_APPLICATION 0x40
+#define DER_CONTEXT_SPECIFIC 0x80
+#define DER_PRIVATE 0xc0
+
+/*
+** Our additions, used for templates.
+** These are not defined by any standard; the values are used internally only.
+** Just be careful to keep them out of the low 8 bits.
+*/
+#define DER_OPTIONAL 0x00100
+#define DER_EXPLICIT 0x00200
+#define DER_ANY 0x00400
+#define DER_INLINE 0x00800
+#define DER_POINTER 0x01000
+#define DER_INDEFINITE 0x02000
+#define DER_DERPTR 0x04000
+#define DER_SKIP 0x08000
+#define DER_FORCE 0x10000
+#define DER_OUTER 0x40000 /* for DER_DERPTR */
+
+/*
+** Macro to convert der decoded bit string into a decoded octet
+** string. All it needs to do is fiddle with the length code.
+*/
+#define DER_ConvertBitString(item) \
+{ \
+ (item)->len = ((item)->len + 7) >> 3; \
+}
+
+#endif /* _SECDERT_H_ */
diff --git a/security/nss/lib/util/secdig.c b/security/nss/lib/util/secdig.c
new file mode 100644
index 000000000..815c5a7c4
--- /dev/null
+++ b/security/nss/lib/util/secdig.c
@@ -0,0 +1,212 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/* $Id$ */
+#include "secdig.h"
+
+#include "secoid.h"
+#include "secasn1.h"
+#include "secerr.h"
+
+/*
+ * XXX Want to have a SGN_DecodeDigestInfo, like:
+ * SGNDigestInfo *SGN_DecodeDigestInfo(SECItem *didata);
+ * that creates a pool and allocates from it and decodes didata into
+ * the newly allocated DigestInfo structure. Then fix secvfy.c (it
+ * will no longer need an arena itself) to call this and then call
+ * DestroyDigestInfo when it is done, then can remove the old template
+ * above and keep our new template static and "hidden".
+ */
+
+/*
+ * XXX It might be nice to combine the following two functions (create
+ * and encode). I think that is all anybody ever wants to do anyway.
+ */
+
+SECItem *
+SGN_EncodeDigestInfo(PRArenaPool *poolp, SECItem *dest, SGNDigestInfo *diginfo)
+{
+ return SEC_ASN1EncodeItem (poolp, dest, diginfo, sgn_DigestInfoTemplate);
+}
+
+SGNDigestInfo *
+SGN_CreateDigestInfo(SECOidTag algorithm, unsigned char *sig, unsigned len)
+{
+ SGNDigestInfo *di;
+ SECStatus rv;
+ PRArenaPool *arena;
+ SECItem *null_param;
+ SECItem dummy_value;
+
+ switch (algorithm) {
+ case SEC_OID_MD2:
+ case SEC_OID_MD5:
+ case SEC_OID_SHA1:
+ case SEC_OID_SHA256:
+ case SEC_OID_SHA384:
+ case SEC_OID_SHA512:
+ break;
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ALGORITHM);
+ return NULL;
+ }
+
+ arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE);
+ if (arena == NULL) {
+ return NULL;
+ }
+
+ di = (SGNDigestInfo *) PORT_ArenaZAlloc(arena, sizeof(SGNDigestInfo));
+ if (di == NULL) {
+ PORT_FreeArena(arena, PR_FALSE);
+ return NULL;
+ }
+
+ di->arena = arena;
+
+ /*
+ * PKCS #1 specifies that the AlgorithmID must have a NULL parameter
+ * (as opposed to no parameter at all).
+ */
+ dummy_value.data = NULL;
+ dummy_value.len = 0;
+ null_param = SEC_ASN1EncodeItem(NULL, NULL, &dummy_value, SEC_NullTemplate);
+ if (null_param == NULL) {
+ goto loser;
+ }
+
+ rv = SECOID_SetAlgorithmID(arena, &di->digestAlgorithm, algorithm,
+ null_param);
+
+ SECITEM_FreeItem(null_param, PR_TRUE);
+
+ if (rv != SECSuccess) {
+ goto loser;
+ }
+
+ di->digest.data = (unsigned char *) PORT_ArenaAlloc(arena, len);
+ if (di->digest.data == NULL) {
+ goto loser;
+ }
+
+ di->digest.len = len;
+ PORT_Memcpy(di->digest.data, sig, len);
+ return di;
+
+ loser:
+ SGN_DestroyDigestInfo(di);
+ return NULL;
+}
+
+SGNDigestInfo *
+SGN_DecodeDigestInfo(SECItem *didata)
+{
+ PRArenaPool *arena;
+ SGNDigestInfo *di;
+ SECStatus rv = SECFailure;
+ SECItem diCopy = {siBuffer, NULL, 0};
+
+ arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE);
+ if(arena == NULL)
+ return NULL;
+
+ rv = SECITEM_CopyItem(arena, &diCopy, didata);
+ if (rv != SECSuccess) {
+ PORT_FreeArena(arena, PR_FALSE);
+ return NULL;
+ }
+
+ di = (SGNDigestInfo *)PORT_ArenaZAlloc(arena, sizeof(SGNDigestInfo));
+ if (di != NULL) {
+ di->arena = arena;
+ rv = SEC_QuickDERDecodeItem(arena, di, sgn_DigestInfoTemplate, &diCopy);
+ }
+
+ if ((di == NULL) || (rv != SECSuccess)) {
+ PORT_FreeArena(arena, PR_FALSE);
+ di = NULL;
+ }
+
+ return di;
+}
+
+void
+SGN_DestroyDigestInfo(SGNDigestInfo *di)
+{
+ if (di && di->arena) {
+ PORT_FreeArena(di->arena, PR_FALSE);
+ }
+
+ return;
+}
+
+SECStatus
+SGN_CopyDigestInfo(PRArenaPool *poolp, SGNDigestInfo *a, SGNDigestInfo *b)
+{
+ SECStatus rv;
+ void *mark;
+
+ if((poolp == NULL) || (a == NULL) || (b == NULL))
+ return SECFailure;
+
+ mark = PORT_ArenaMark(poolp);
+ a->arena = poolp;
+ rv = SECOID_CopyAlgorithmID(poolp, &a->digestAlgorithm,
+ &b->digestAlgorithm);
+ if (rv == SECSuccess)
+ rv = SECITEM_CopyItem(poolp, &a->digest, &b->digest);
+
+ if (rv != SECSuccess) {
+ PORT_ArenaRelease(poolp, mark);
+ } else {
+ PORT_ArenaUnmark(poolp, mark);
+ }
+
+ return rv;
+}
+
+SECComparison
+SGN_CompareDigestInfo(SGNDigestInfo *a, SGNDigestInfo *b)
+{
+ SECComparison rv;
+
+ /* Check signature algorithm's */
+ rv = SECOID_CompareAlgorithmID(&a->digestAlgorithm, &b->digestAlgorithm);
+ if (rv) return rv;
+
+ /* Compare signature block length's */
+ rv = SECITEM_CompareItem(&a->digest, &b->digest);
+ return rv;
+}
diff --git a/security/nss/lib/util/secdig.h b/security/nss/lib/util/secdig.h
new file mode 100644
index 000000000..1319abdb2
--- /dev/null
+++ b/security/nss/lib/util/secdig.h
@@ -0,0 +1,136 @@
+/*
+ * crypto.h - public data structures and prototypes for the crypto library
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/* $Id$ */
+
+#ifndef _SECDIG_H_
+#define _SECDIG_H_
+
+#include "utilrename.h"
+#include "secdigt.h"
+
+#include "seccomon.h"
+#include "secasn1t.h"
+#include "secdert.h"
+
+SEC_BEGIN_PROTOS
+
+
+extern const SEC_ASN1Template sgn_DigestInfoTemplate[];
+
+SEC_ASN1_CHOOSER_DECLARE(sgn_DigestInfoTemplate)
+
+/****************************************/
+/*
+** Digest-info functions
+*/
+
+/*
+** Create a new digest-info object
+** "algorithm" one of SEC_OID_MD2, SEC_OID_MD5, or SEC_OID_SHA1
+** "sig" the raw signature data (from MD2 or MD5)
+** "sigLen" the length of the signature data
+**
+** NOTE: this is a low level routine used to prepare some data for PKCS#1
+** digital signature formatting.
+**
+** XXX It might be nice to combine the create and encode functions.
+** I think that is all anybody ever wants to do anyway.
+*/
+extern SGNDigestInfo *SGN_CreateDigestInfo(SECOidTag algorithm,
+ unsigned char *sig,
+ unsigned int sigLen);
+
+/*
+** Destroy a digest-info object
+*/
+extern void SGN_DestroyDigestInfo(SGNDigestInfo *info);
+
+/*
+** Encode a digest-info object
+** "poolp" is where to allocate the result from; it can be NULL in
+** which case generic heap allocation (XP_ALLOC) will be used
+** "dest" is where to store the result; it can be NULL, in which case
+** it will be allocated (from poolp or heap, as explained above)
+** "diginfo" is the object to be encoded
+** The return value is NULL if any error occurred, otherwise it is the
+** resulting SECItem (either allocated or the same as the "dest" parameter).
+**
+** XXX It might be nice to combine the create and encode functions.
+** I think that is all anybody ever wants to do anyway.
+*/
+extern SECItem *SGN_EncodeDigestInfo(PLArenaPool *poolp, SECItem *dest,
+ SGNDigestInfo *diginfo);
+
+/*
+** Decode a DER encoded digest info objct.
+** didata is thr source of the encoded digest.
+** The return value is NULL if an error occurs. Otherwise, a
+** digest info object which is allocated within it's own
+** pool is returned. The digest info should be deleted
+** by later calling SGN_DestroyDigestInfo.
+*/
+extern SGNDigestInfo *SGN_DecodeDigestInfo(SECItem *didata);
+
+
+/*
+** Copy digest info.
+** poolp is the arena to which the digest will be copied.
+** a is the destination digest, it must be non-NULL.
+** b is the source digest
+** This function is for copying digests. It allows digests
+** to be copied into a specified pool. If the digest is in
+** the same pool as other data, you do not want to delete
+** the digest by calling SGN_DestroyDigestInfo.
+** A return value of SECFailure indicates an error. A return
+** of SECSuccess indicates no error occured.
+*/
+extern SECStatus SGN_CopyDigestInfo(PLArenaPool *poolp,
+ SGNDigestInfo *a,
+ SGNDigestInfo *b);
+
+/*
+** Compare two digest-info objects, returning the difference between
+** them.
+*/
+extern SECComparison SGN_CompareDigestInfo(SGNDigestInfo *a, SGNDigestInfo *b);
+
+
+SEC_END_PROTOS
+
+#endif /* _SECDIG_H_ */
diff --git a/security/nss/lib/util/secdigt.h b/security/nss/lib/util/secdigt.h
new file mode 100644
index 000000000..aee02d793
--- /dev/null
+++ b/security/nss/lib/util/secdigt.h
@@ -0,0 +1,61 @@
+/*
+ * secdigt.h - public data structures for digestinfos from the util lib.
+ *
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+/* $Id$ */
+
+#ifndef _SECDIGT_H_
+#define _SECDIGT_H_
+
+#include "utilrename.h"
+#include "plarena.h"
+#include "secoidt.h"
+#include "secitem.h"
+
+/*
+** A PKCS#1 digest-info object
+*/
+struct SGNDigestInfoStr {
+ PLArenaPool * arena;
+ SECAlgorithmID digestAlgorithm;
+ SECItem digest;
+};
+typedef struct SGNDigestInfoStr SGNDigestInfo;
+
+
+
+#endif /* _SECDIGT_H_ */
diff --git a/security/nss/lib/util/secerr.h b/security/nss/lib/util/secerr.h
new file mode 100644
index 000000000..0c29838cc
--- /dev/null
+++ b/security/nss/lib/util/secerr.h
@@ -0,0 +1,233 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __SEC_ERR_H_
+#define __SEC_ERR_H_
+
+#include "utilrename.h"
+
+#define SEC_ERROR_BASE (-0x2000)
+#define SEC_ERROR_LIMIT (SEC_ERROR_BASE + 1000)
+
+#define IS_SEC_ERROR(code) \
+ (((code) >= SEC_ERROR_BASE) && ((code) < SEC_ERROR_LIMIT))
+
+#ifndef NO_SECURITY_ERROR_ENUM
+typedef enum {
+SEC_ERROR_IO = SEC_ERROR_BASE + 0,
+SEC_ERROR_LIBRARY_FAILURE = SEC_ERROR_BASE + 1,
+SEC_ERROR_BAD_DATA = SEC_ERROR_BASE + 2,
+SEC_ERROR_OUTPUT_LEN = SEC_ERROR_BASE + 3,
+SEC_ERROR_INPUT_LEN = SEC_ERROR_BASE + 4,
+SEC_ERROR_INVALID_ARGS = SEC_ERROR_BASE + 5,
+SEC_ERROR_INVALID_ALGORITHM = SEC_ERROR_BASE + 6,
+SEC_ERROR_INVALID_AVA = SEC_ERROR_BASE + 7,
+SEC_ERROR_INVALID_TIME = SEC_ERROR_BASE + 8,
+SEC_ERROR_BAD_DER = SEC_ERROR_BASE + 9,
+SEC_ERROR_BAD_SIGNATURE = SEC_ERROR_BASE + 10,
+SEC_ERROR_EXPIRED_CERTIFICATE = SEC_ERROR_BASE + 11,
+SEC_ERROR_REVOKED_CERTIFICATE = SEC_ERROR_BASE + 12,
+SEC_ERROR_UNKNOWN_ISSUER = SEC_ERROR_BASE + 13,
+SEC_ERROR_BAD_KEY = SEC_ERROR_BASE + 14,
+SEC_ERROR_BAD_PASSWORD = SEC_ERROR_BASE + 15,
+SEC_ERROR_RETRY_PASSWORD = SEC_ERROR_BASE + 16,
+SEC_ERROR_NO_NODELOCK = SEC_ERROR_BASE + 17,
+SEC_ERROR_BAD_DATABASE = SEC_ERROR_BASE + 18,
+SEC_ERROR_NO_MEMORY = SEC_ERROR_BASE + 19,
+SEC_ERROR_UNTRUSTED_ISSUER = SEC_ERROR_BASE + 20,
+SEC_ERROR_UNTRUSTED_CERT = SEC_ERROR_BASE + 21,
+SEC_ERROR_DUPLICATE_CERT = (SEC_ERROR_BASE + 22),
+SEC_ERROR_DUPLICATE_CERT_NAME = (SEC_ERROR_BASE + 23),
+SEC_ERROR_ADDING_CERT = (SEC_ERROR_BASE + 24),
+SEC_ERROR_FILING_KEY = (SEC_ERROR_BASE + 25),
+SEC_ERROR_NO_KEY = (SEC_ERROR_BASE + 26),
+SEC_ERROR_CERT_VALID = (SEC_ERROR_BASE + 27),
+SEC_ERROR_CERT_NOT_VALID = (SEC_ERROR_BASE + 28),
+SEC_ERROR_CERT_NO_RESPONSE = (SEC_ERROR_BASE + 29),
+SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE = (SEC_ERROR_BASE + 30),
+SEC_ERROR_CRL_EXPIRED = (SEC_ERROR_BASE + 31),
+SEC_ERROR_CRL_BAD_SIGNATURE = (SEC_ERROR_BASE + 32),
+SEC_ERROR_CRL_INVALID = (SEC_ERROR_BASE + 33),
+SEC_ERROR_EXTENSION_VALUE_INVALID = (SEC_ERROR_BASE + 34),
+SEC_ERROR_EXTENSION_NOT_FOUND = (SEC_ERROR_BASE + 35),
+SEC_ERROR_CA_CERT_INVALID = (SEC_ERROR_BASE + 36),
+SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID = (SEC_ERROR_BASE + 37),
+SEC_ERROR_CERT_USAGES_INVALID = (SEC_ERROR_BASE + 38),
+SEC_INTERNAL_ONLY = (SEC_ERROR_BASE + 39),
+SEC_ERROR_INVALID_KEY = (SEC_ERROR_BASE + 40),
+SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION = (SEC_ERROR_BASE + 41),
+SEC_ERROR_OLD_CRL = (SEC_ERROR_BASE + 42),
+SEC_ERROR_NO_EMAIL_CERT = (SEC_ERROR_BASE + 43),
+SEC_ERROR_NO_RECIPIENT_CERTS_QUERY = (SEC_ERROR_BASE + 44),
+SEC_ERROR_NOT_A_RECIPIENT = (SEC_ERROR_BASE + 45),
+SEC_ERROR_PKCS7_KEYALG_MISMATCH = (SEC_ERROR_BASE + 46),
+SEC_ERROR_PKCS7_BAD_SIGNATURE = (SEC_ERROR_BASE + 47),
+SEC_ERROR_UNSUPPORTED_KEYALG = (SEC_ERROR_BASE + 48),
+SEC_ERROR_DECRYPTION_DISALLOWED = (SEC_ERROR_BASE + 49),
+/* Fortezza Alerts */
+XP_SEC_FORTEZZA_BAD_CARD = (SEC_ERROR_BASE + 50),
+XP_SEC_FORTEZZA_NO_CARD = (SEC_ERROR_BASE + 51),
+XP_SEC_FORTEZZA_NONE_SELECTED = (SEC_ERROR_BASE + 52),
+XP_SEC_FORTEZZA_MORE_INFO = (SEC_ERROR_BASE + 53),
+XP_SEC_FORTEZZA_PERSON_NOT_FOUND = (SEC_ERROR_BASE + 54),
+XP_SEC_FORTEZZA_NO_MORE_INFO = (SEC_ERROR_BASE + 55),
+XP_SEC_FORTEZZA_BAD_PIN = (SEC_ERROR_BASE + 56),
+XP_SEC_FORTEZZA_PERSON_ERROR = (SEC_ERROR_BASE + 57),
+SEC_ERROR_NO_KRL = (SEC_ERROR_BASE + 58),
+SEC_ERROR_KRL_EXPIRED = (SEC_ERROR_BASE + 59),
+SEC_ERROR_KRL_BAD_SIGNATURE = (SEC_ERROR_BASE + 60),
+SEC_ERROR_REVOKED_KEY = (SEC_ERROR_BASE + 61),
+SEC_ERROR_KRL_INVALID = (SEC_ERROR_BASE + 62),
+SEC_ERROR_NEED_RANDOM = (SEC_ERROR_BASE + 63),
+SEC_ERROR_NO_MODULE = (SEC_ERROR_BASE + 64),
+SEC_ERROR_NO_TOKEN = (SEC_ERROR_BASE + 65),
+SEC_ERROR_READ_ONLY = (SEC_ERROR_BASE + 66),
+SEC_ERROR_NO_SLOT_SELECTED = (SEC_ERROR_BASE + 67),
+SEC_ERROR_CERT_NICKNAME_COLLISION = (SEC_ERROR_BASE + 68),
+SEC_ERROR_KEY_NICKNAME_COLLISION = (SEC_ERROR_BASE + 69),
+SEC_ERROR_SAFE_NOT_CREATED = (SEC_ERROR_BASE + 70),
+SEC_ERROR_BAGGAGE_NOT_CREATED = (SEC_ERROR_BASE + 71),
+XP_JAVA_REMOVE_PRINCIPAL_ERROR = (SEC_ERROR_BASE + 72),
+XP_JAVA_DELETE_PRIVILEGE_ERROR = (SEC_ERROR_BASE + 73),
+XP_JAVA_CERT_NOT_EXISTS_ERROR = (SEC_ERROR_BASE + 74),
+SEC_ERROR_BAD_EXPORT_ALGORITHM = (SEC_ERROR_BASE + 75),
+SEC_ERROR_EXPORTING_CERTIFICATES = (SEC_ERROR_BASE + 76),
+SEC_ERROR_IMPORTING_CERTIFICATES = (SEC_ERROR_BASE + 77),
+SEC_ERROR_PKCS12_DECODING_PFX = (SEC_ERROR_BASE + 78),
+SEC_ERROR_PKCS12_INVALID_MAC = (SEC_ERROR_BASE + 79),
+SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM = (SEC_ERROR_BASE + 80),
+SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE = (SEC_ERROR_BASE + 81),
+SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE = (SEC_ERROR_BASE + 82),
+SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM = (SEC_ERROR_BASE + 83),
+SEC_ERROR_PKCS12_UNSUPPORTED_VERSION = (SEC_ERROR_BASE + 84),
+SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT = (SEC_ERROR_BASE + 85),
+SEC_ERROR_PKCS12_CERT_COLLISION = (SEC_ERROR_BASE + 86),
+SEC_ERROR_USER_CANCELLED = (SEC_ERROR_BASE + 87),
+SEC_ERROR_PKCS12_DUPLICATE_DATA = (SEC_ERROR_BASE + 88),
+SEC_ERROR_MESSAGE_SEND_ABORTED = (SEC_ERROR_BASE + 89),
+SEC_ERROR_INADEQUATE_KEY_USAGE = (SEC_ERROR_BASE + 90),
+SEC_ERROR_INADEQUATE_CERT_TYPE = (SEC_ERROR_BASE + 91),
+SEC_ERROR_CERT_ADDR_MISMATCH = (SEC_ERROR_BASE + 92),
+SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY = (SEC_ERROR_BASE + 93),
+SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN = (SEC_ERROR_BASE + 94),
+SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME = (SEC_ERROR_BASE + 95),
+SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY = (SEC_ERROR_BASE + 96),
+SEC_ERROR_PKCS12_UNABLE_TO_WRITE = (SEC_ERROR_BASE + 97),
+SEC_ERROR_PKCS12_UNABLE_TO_READ = (SEC_ERROR_BASE + 98),
+SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED = (SEC_ERROR_BASE + 99),
+SEC_ERROR_KEYGEN_FAIL = (SEC_ERROR_BASE + 100),
+SEC_ERROR_INVALID_PASSWORD = (SEC_ERROR_BASE + 101),
+SEC_ERROR_RETRY_OLD_PASSWORD = (SEC_ERROR_BASE + 102),
+SEC_ERROR_BAD_NICKNAME = (SEC_ERROR_BASE + 103),
+SEC_ERROR_NOT_FORTEZZA_ISSUER = (SEC_ERROR_BASE + 104),
+SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY = (SEC_ERROR_BASE + 105),
+SEC_ERROR_JS_INVALID_MODULE_NAME = (SEC_ERROR_BASE + 106),
+SEC_ERROR_JS_INVALID_DLL = (SEC_ERROR_BASE + 107),
+SEC_ERROR_JS_ADD_MOD_FAILURE = (SEC_ERROR_BASE + 108),
+SEC_ERROR_JS_DEL_MOD_FAILURE = (SEC_ERROR_BASE + 109),
+SEC_ERROR_OLD_KRL = (SEC_ERROR_BASE + 110),
+SEC_ERROR_CKL_CONFLICT = (SEC_ERROR_BASE + 111),
+SEC_ERROR_CERT_NOT_IN_NAME_SPACE = (SEC_ERROR_BASE + 112),
+SEC_ERROR_KRL_NOT_YET_VALID = (SEC_ERROR_BASE + 113),
+SEC_ERROR_CRL_NOT_YET_VALID = (SEC_ERROR_BASE + 114),
+SEC_ERROR_UNKNOWN_CERT = (SEC_ERROR_BASE + 115),
+SEC_ERROR_UNKNOWN_SIGNER = (SEC_ERROR_BASE + 116),
+SEC_ERROR_CERT_BAD_ACCESS_LOCATION = (SEC_ERROR_BASE + 117),
+SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE = (SEC_ERROR_BASE + 118),
+SEC_ERROR_OCSP_BAD_HTTP_RESPONSE = (SEC_ERROR_BASE + 119),
+SEC_ERROR_OCSP_MALFORMED_REQUEST = (SEC_ERROR_BASE + 120),
+SEC_ERROR_OCSP_SERVER_ERROR = (SEC_ERROR_BASE + 121),
+SEC_ERROR_OCSP_TRY_SERVER_LATER = (SEC_ERROR_BASE + 122),
+SEC_ERROR_OCSP_REQUEST_NEEDS_SIG = (SEC_ERROR_BASE + 123),
+SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST = (SEC_ERROR_BASE + 124),
+SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS = (SEC_ERROR_BASE + 125),
+SEC_ERROR_OCSP_UNKNOWN_CERT = (SEC_ERROR_BASE + 126),
+SEC_ERROR_OCSP_NOT_ENABLED = (SEC_ERROR_BASE + 127),
+SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER = (SEC_ERROR_BASE + 128),
+SEC_ERROR_OCSP_MALFORMED_RESPONSE = (SEC_ERROR_BASE + 129),
+SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE = (SEC_ERROR_BASE + 130),
+SEC_ERROR_OCSP_FUTURE_RESPONSE = (SEC_ERROR_BASE + 131),
+SEC_ERROR_OCSP_OLD_RESPONSE = (SEC_ERROR_BASE + 132),
+/* smime stuff */
+SEC_ERROR_DIGEST_NOT_FOUND = (SEC_ERROR_BASE + 133),
+SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE = (SEC_ERROR_BASE + 134),
+SEC_ERROR_MODULE_STUCK = (SEC_ERROR_BASE + 135),
+SEC_ERROR_BAD_TEMPLATE = (SEC_ERROR_BASE + 136),
+SEC_ERROR_CRL_NOT_FOUND = (SEC_ERROR_BASE + 137),
+SEC_ERROR_REUSED_ISSUER_AND_SERIAL = (SEC_ERROR_BASE + 138),
+SEC_ERROR_BUSY = (SEC_ERROR_BASE + 139),
+SEC_ERROR_EXTRA_INPUT = (SEC_ERROR_BASE + 140),
+/* error codes used by elliptic curve code */
+SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE = (SEC_ERROR_BASE + 141),
+SEC_ERROR_UNSUPPORTED_EC_POINT_FORM = (SEC_ERROR_BASE + 142),
+SEC_ERROR_UNRECOGNIZED_OID = (SEC_ERROR_BASE + 143),
+SEC_ERROR_OCSP_INVALID_SIGNING_CERT = (SEC_ERROR_BASE + 144),
+/* new revocation errors */
+SEC_ERROR_REVOKED_CERTIFICATE_CRL = (SEC_ERROR_BASE + 145),
+SEC_ERROR_REVOKED_CERTIFICATE_OCSP = (SEC_ERROR_BASE + 146),
+SEC_ERROR_CRL_INVALID_VERSION = (SEC_ERROR_BASE + 147),
+SEC_ERROR_CRL_V1_CRITICAL_EXTENSION = (SEC_ERROR_BASE + 148),
+SEC_ERROR_CRL_UNKNOWN_CRITICAL_EXTENSION = (SEC_ERROR_BASE + 149),
+SEC_ERROR_UNKNOWN_OBJECT_TYPE = (SEC_ERROR_BASE + 150),
+SEC_ERROR_INCOMPATIBLE_PKCS11 = (SEC_ERROR_BASE + 151),
+SEC_ERROR_NO_EVENT = (SEC_ERROR_BASE + 152),
+SEC_ERROR_CRL_ALREADY_EXISTS = (SEC_ERROR_BASE + 153),
+SEC_ERROR_NOT_INITIALIZED = (SEC_ERROR_BASE + 154),
+SEC_ERROR_TOKEN_NOT_LOGGED_IN = (SEC_ERROR_BASE + 155),
+SEC_ERROR_OCSP_RESPONDER_CERT_INVALID = (SEC_ERROR_BASE + 156),
+SEC_ERROR_OCSP_BAD_SIGNATURE = (SEC_ERROR_BASE + 157),
+
+SEC_ERROR_OUT_OF_SEARCH_LIMITS = (SEC_ERROR_BASE + 158),
+SEC_ERROR_INVALID_POLICY_MAPPING = (SEC_ERROR_BASE + 159),
+SEC_ERROR_POLICY_VALIDATION_FAILED = (SEC_ERROR_BASE + 160),
+SEC_ERROR_UNKNOWN_AIA_LOCATION_TYPE = (SEC_ERROR_BASE + 161),
+SEC_ERROR_BAD_HTTP_RESPONSE = (SEC_ERROR_BASE + 162),
+SEC_ERROR_BAD_LDAP_RESPONSE = (SEC_ERROR_BASE + 163),
+SEC_ERROR_FAILED_TO_ENCODE_DATA = (SEC_ERROR_BASE + 164),
+SEC_ERROR_BAD_INFO_ACCESS_LOCATION = (SEC_ERROR_BASE + 165),
+
+SEC_ERROR_LIBPKIX_INTERNAL = (SEC_ERROR_BASE + 166),
+
+SEC_ERROR_PKCS11_GENERAL_ERROR = (SEC_ERROR_BASE + 167),
+SEC_ERROR_PKCS11_FUNCTION_FAILED = (SEC_ERROR_BASE + 168),
+SEC_ERROR_PKCS11_DEVICE_ERROR = (SEC_ERROR_BASE + 169),
+
+/* Add new error codes above here. */
+SEC_ERROR_END_OF_LIST
+} SECErrorCodes;
+#endif /* NO_SECURITY_ERROR_ENUM */
+
+#endif /* __SEC_ERR_H_ */
diff --git a/security/nss/lib/util/secinit.c b/security/nss/lib/util/secinit.c
new file mode 100644
index 000000000..c62d83a80
--- /dev/null
+++ b/security/nss/lib/util/secinit.c
@@ -0,0 +1,53 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nspr.h"
+#include "secport.h"
+
+static int sec_inited = 0;
+
+void
+SEC_Init(void)
+{
+ /* PR_Init() must be called before SEC_Init() */
+#if !defined(SERVER_BUILD)
+ PORT_Assert(PR_Initialized() == PR_TRUE);
+#endif
+ if (sec_inited)
+ return;
+
+ sec_inited = 1;
+}
diff --git a/security/nss/lib/util/secitem.c b/security/nss/lib/util/secitem.c
new file mode 100644
index 000000000..74396571b
--- /dev/null
+++ b/security/nss/lib/util/secitem.c
@@ -0,0 +1,322 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Support routines for SECItem data structure.
+ *
+ * $Id$
+ */
+
+#include "seccomon.h"
+#include "secitem.h"
+#include "base64.h"
+#include "secerr.h"
+
+SECItem *
+SECITEM_AllocItem(PRArenaPool *arena, SECItem *item, unsigned int len)
+{
+ SECItem *result = NULL;
+ void *mark = NULL;
+
+ if (arena != NULL) {
+ mark = PORT_ArenaMark(arena);
+ }
+
+ if (item == NULL) {
+ if (arena != NULL) {
+ result = PORT_ArenaZAlloc(arena, sizeof(SECItem));
+ } else {
+ result = PORT_ZAlloc(sizeof(SECItem));
+ }
+ if (result == NULL) {
+ goto loser;
+ }
+ } else {
+ PORT_Assert(item->data == NULL);
+ result = item;
+ }
+
+ result->len = len;
+ if (len) {
+ if (arena != NULL) {
+ result->data = PORT_ArenaAlloc(arena, len);
+ } else {
+ result->data = PORT_Alloc(len);
+ }
+ if (result->data == NULL) {
+ goto loser;
+ }
+ } else {
+ result->data = NULL;
+ }
+
+ if (mark) {
+ PORT_ArenaUnmark(arena, mark);
+ }
+ return(result);
+
+loser:
+ if ( arena != NULL ) {
+ if (mark) {
+ PORT_ArenaRelease(arena, mark);
+ }
+ if (item != NULL) {
+ item->data = NULL;
+ item->len = 0;
+ }
+ } else {
+ if (result != NULL) {
+ SECITEM_FreeItem(result, (item == NULL) ? PR_TRUE : PR_FALSE);
+ }
+ /*
+ * If item is not NULL, the above has set item->data and
+ * item->len to 0.
+ */
+ }
+ return(NULL);
+}
+
+SECStatus
+SECITEM_ReallocItem(PRArenaPool *arena, SECItem *item, unsigned int oldlen,
+ unsigned int newlen)
+{
+ PORT_Assert(item != NULL);
+ if (item == NULL) {
+ /* XXX Set error. But to what? */
+ return SECFailure;
+ }
+
+ /*
+ * If no old length, degenerate to just plain alloc.
+ */
+ if (oldlen == 0) {
+ PORT_Assert(item->data == NULL || item->len == 0);
+ if (newlen == 0) {
+ /* Nothing to do. Weird, but not a failure. */
+ return SECSuccess;
+ }
+ item->len = newlen;
+ if (arena != NULL) {
+ item->data = PORT_ArenaAlloc(arena, newlen);
+ } else {
+ item->data = PORT_Alloc(newlen);
+ }
+ } else {
+ if (arena != NULL) {
+ item->data = PORT_ArenaGrow(arena, item->data, oldlen, newlen);
+ } else {
+ item->data = PORT_Realloc(item->data, newlen);
+ }
+ }
+
+ if (item->data == NULL) {
+ return SECFailure;
+ }
+
+ return SECSuccess;
+}
+
+SECComparison
+SECITEM_CompareItem(const SECItem *a, const SECItem *b)
+{
+ unsigned m;
+ SECComparison rv;
+
+ if (!a || !a->len || !a->data)
+ return (!b || !b->len || !b->data) ? SECEqual : SECLessThan;
+ if (!b || !b->len || !b->data)
+ return SECGreaterThan;
+
+ m = ( ( a->len < b->len ) ? a->len : b->len );
+
+ rv = (SECComparison) PORT_Memcmp(a->data, b->data, m);
+ if (rv) {
+ return rv;
+ }
+ if (a->len < b->len) {
+ return SECLessThan;
+ }
+ if (a->len == b->len) {
+ return SECEqual;
+ }
+ return SECGreaterThan;
+}
+
+PRBool
+SECITEM_ItemsAreEqual(const SECItem *a, const SECItem *b)
+{
+ if (a->len != b->len)
+ return PR_FALSE;
+ if (!a->len)
+ return PR_TRUE;
+ if (!a->data || !b->data) {
+ /* avoid null pointer crash. */
+ return (PRBool)(a->data == b->data);
+ }
+ return (PRBool)!PORT_Memcmp(a->data, b->data, a->len);
+}
+
+SECItem *
+SECITEM_DupItem(const SECItem *from)
+{
+ return SECITEM_ArenaDupItem(NULL, from);
+}
+
+SECItem *
+SECITEM_ArenaDupItem(PRArenaPool *arena, const SECItem *from)
+{
+ SECItem *to;
+
+ if ( from == NULL ) {
+ return(NULL);
+ }
+
+ if ( arena != NULL ) {
+ to = (SECItem *)PORT_ArenaAlloc(arena, sizeof(SECItem));
+ } else {
+ to = (SECItem *)PORT_Alloc(sizeof(SECItem));
+ }
+ if ( to == NULL ) {
+ return(NULL);
+ }
+
+ if ( arena != NULL ) {
+ to->data = (unsigned char *)PORT_ArenaAlloc(arena, from->len);
+ } else {
+ to->data = (unsigned char *)PORT_Alloc(from->len);
+ }
+ if ( to->data == NULL ) {
+ PORT_Free(to);
+ return(NULL);
+ }
+
+ to->len = from->len;
+ to->type = from->type;
+ if ( to->len ) {
+ PORT_Memcpy(to->data, from->data, to->len);
+ }
+
+ return(to);
+}
+
+SECStatus
+SECITEM_CopyItem(PRArenaPool *arena, SECItem *to, const SECItem *from)
+{
+ to->type = from->type;
+ if (from->data && from->len) {
+ if ( arena ) {
+ to->data = (unsigned char*) PORT_ArenaAlloc(arena, from->len);
+ } else {
+ to->data = (unsigned char*) PORT_Alloc(from->len);
+ }
+
+ if (!to->data) {
+ return SECFailure;
+ }
+ PORT_Memcpy(to->data, from->data, from->len);
+ to->len = from->len;
+ } else {
+ to->data = 0;
+ to->len = 0;
+ }
+ return SECSuccess;
+}
+
+void
+SECITEM_FreeItem(SECItem *zap, PRBool freeit)
+{
+ if (zap) {
+ PORT_Free(zap->data);
+ zap->data = 0;
+ zap->len = 0;
+ if (freeit) {
+ PORT_Free(zap);
+ }
+ }
+}
+
+void
+SECITEM_ZfreeItem(SECItem *zap, PRBool freeit)
+{
+ if (zap) {
+ PORT_ZFree(zap->data, zap->len);
+ zap->data = 0;
+ zap->len = 0;
+ if (freeit) {
+ PORT_ZFree(zap, sizeof(SECItem));
+ }
+ }
+}
+/* these reroutines were taken from pkix oid.c, which is supposed to
+ * replace this file some day */
+/*
+ * This is the hash function. We simply XOR the encoded form with
+ * itself in sizeof(PLHashNumber)-byte chunks. Improving this
+ * routine is left as an excercise for the more mathematically
+ * inclined student.
+ */
+PLHashNumber PR_CALLBACK
+SECITEM_Hash ( const void *key)
+{
+ const SECItem *item = (const SECItem *)key;
+ PLHashNumber rv = 0;
+
+ PRUint8 *data = (PRUint8 *)item->data;
+ PRUint32 i;
+ PRUint8 *rvc = (PRUint8 *)&rv;
+
+ for( i = 0; i < item->len; i++ ) {
+ rvc[ i % sizeof(rv) ] ^= *data;
+ data++;
+ }
+
+ return rv;
+}
+
+/*
+ * This is the key-compare function. It simply does a lexical
+ * comparison on the item data. This does not result in
+ * quite the same ordering as the "sequence of numbers" order,
+ * but heck it's only used internally by the hash table anyway.
+ */
+PRIntn PR_CALLBACK
+SECITEM_HashCompare ( const void *k1, const void *k2)
+{
+ const SECItem *i1 = (const SECItem *)k1;
+ const SECItem *i2 = (const SECItem *)k2;
+
+ return SECITEM_ItemsAreEqual(i1,i2);
+}
diff --git a/security/nss/lib/util/secitem.h b/security/nss/lib/util/secitem.h
new file mode 100644
index 000000000..de3df877f
--- /dev/null
+++ b/security/nss/lib/util/secitem.h
@@ -0,0 +1,128 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _SECITEM_H_
+#define _SECITEM_H_
+
+#include "utilrename.h"
+
+/*
+ * secitem.h - public data structures and prototypes for handling
+ * SECItems
+ *
+ * $Id$
+ */
+
+#include "plarena.h"
+#include "plhash.h"
+#include "seccomon.h"
+
+SEC_BEGIN_PROTOS
+
+/*
+** Allocate an item. If "arena" is not NULL, then allocate from there,
+** otherwise allocate from the heap. If "item" is not NULL, allocate
+** only the data buffer for the item, not the item itself. If "len" is
+** 0, do not allocate the data buffer for the item; simply set the data
+** field to NULL and the len field to 0. The item structure is allocated
+** zero-filled; the data buffer is not zeroed. The caller is responsible
+** for initializing the type field of the item.
+**
+** The resulting item is returned; NULL if any error occurs.
+**
+** XXX This probably should take a SECItemType, but since that is mostly
+** unused and our improved APIs (aka Stan) are looming, I left it out.
+*/
+extern SECItem *SECITEM_AllocItem(PLArenaPool *arena, SECItem *item,
+ unsigned int len);
+
+/*
+** Reallocate the data for the specified "item". If "arena" is not NULL,
+** then reallocate from there, otherwise reallocate from the heap.
+** In the case where oldlen is 0, the data is allocated (not reallocated).
+** In any case, "item" is expected to be a valid SECItem pointer;
+** SECFailure is returned if it is not. If the allocation succeeds,
+** SECSuccess is returned.
+*/
+extern SECStatus SECITEM_ReallocItem(PLArenaPool *arena, SECItem *item,
+ unsigned int oldlen, unsigned int newlen);
+
+/*
+** Compare two items returning the difference between them.
+*/
+extern SECComparison SECITEM_CompareItem(const SECItem *a, const SECItem *b);
+
+/*
+** Compare two items -- if they are the same, return true; otherwise false.
+*/
+extern PRBool SECITEM_ItemsAreEqual(const SECItem *a, const SECItem *b);
+
+/*
+** Copy "from" to "to"
+*/
+extern SECStatus SECITEM_CopyItem(PLArenaPool *arena, SECItem *to,
+ const SECItem *from);
+
+/*
+** Allocate an item and copy "from" into it.
+*/
+extern SECItem *SECITEM_DupItem(const SECItem *from);
+
+/*
+** Allocate an item and copy "from" into it. The item itself and the
+** data it points to are both allocated from the arena. If arena is
+** NULL, this function is equivalent to SECITEM_DupItem.
+*/
+extern SECItem *SECITEM_ArenaDupItem(PLArenaPool *arena, const SECItem *from);
+
+/*
+** Free "zap". If freeit is PR_TRUE then "zap" itself is freed.
+*/
+extern void SECITEM_FreeItem(SECItem *zap, PRBool freeit);
+
+/*
+** Zero and then free "zap". If freeit is PR_TRUE then "zap" itself is freed.
+*/
+extern void SECITEM_ZfreeItem(SECItem *zap, PRBool freeit);
+
+PLHashNumber PR_CALLBACK SECITEM_Hash ( const void *key);
+
+PRIntn PR_CALLBACK SECITEM_HashCompare ( const void *k1, const void *k2);
+
+
+SEC_END_PROTOS
+
+#endif /* _SECITEM_H_ */
diff --git a/security/nss/lib/util/secoid.c b/security/nss/lib/util/secoid.c
new file mode 100644
index 000000000..16389e553
--- /dev/null
+++ b/security/nss/lib/util/secoid.c
@@ -0,0 +1,1976 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "secoid.h"
+#include "pkcs11t.h"
+#include "secitem.h"
+#include "secerr.h"
+#include "plhash.h"
+#include "nssrwlk.h"
+
+/* MISSI Mosaic Object ID space */
+#define USGOV 0x60, 0x86, 0x48, 0x01, 0x65
+#define MISSI USGOV, 0x02, 0x01, 0x01
+#define MISSI_OLD_KEA_DSS MISSI, 0x0c
+#define MISSI_OLD_DSS MISSI, 0x02
+#define MISSI_KEA_DSS MISSI, 0x14
+#define MISSI_DSS MISSI, 0x13
+#define MISSI_KEA MISSI, 0x0a
+#define MISSI_ALT_KEA MISSI, 0x16
+
+#define NISTALGS USGOV, 3, 4
+#define AES NISTALGS, 1
+#define SHAXXX NISTALGS, 2
+
+/**
+ ** The Netscape OID space is allocated by Terry Hayes. If you need
+ ** a piece of the space, contact him at thayes@netscape.com.
+ **/
+
+/* Netscape Communications Corporation Object ID space */
+/* { 2 16 840 1 113730 } */
+#define NETSCAPE_OID 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42
+#define NETSCAPE_CERT_EXT NETSCAPE_OID, 0x01
+#define NETSCAPE_DATA_TYPE NETSCAPE_OID, 0x02
+/* netscape directory oid - owned by Mark Smith (mcs@netscape.com) */
+#define NETSCAPE_DIRECTORY NETSCAPE_OID, 0x03
+#define NETSCAPE_POLICY NETSCAPE_OID, 0x04
+#define NETSCAPE_CERT_SERVER NETSCAPE_OID, 0x05
+#define NETSCAPE_ALGS NETSCAPE_OID, 0x06 /* algorithm OIDs */
+#define NETSCAPE_NAME_COMPONENTS NETSCAPE_OID, 0x07
+
+#define NETSCAPE_CERT_EXT_AIA NETSCAPE_CERT_EXT, 0x10
+#define NETSCAPE_CERT_SERVER_CRMF NETSCAPE_CERT_SERVER, 0x01
+
+/* these are old and should go away soon */
+#define OLD_NETSCAPE 0x60, 0x86, 0x48, 0xd8, 0x6a
+#define NS_CERT_EXT OLD_NETSCAPE, 0x01
+#define NS_FILE_TYPE OLD_NETSCAPE, 0x02
+#define NS_IMAGE_TYPE OLD_NETSCAPE, 0x03
+
+/* RSA OID name space */
+#define RSADSI 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d
+#define PKCS RSADSI, 0x01
+#define DIGEST RSADSI, 0x02
+#define CIPHER RSADSI, 0x03
+#define PKCS1 PKCS, 0x01
+#define PKCS5 PKCS, 0x05
+#define PKCS7 PKCS, 0x07
+#define PKCS9 PKCS, 0x09
+#define PKCS12 PKCS, 0x0c
+
+/* Fortezza algorithm OID space: { 2 16 840 1 101 2 1 1 } */
+/* ### mwelch -- Is this just for algorithms, or all of Fortezza? */
+#define FORTEZZA_ALG 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x01
+
+/* Other OID name spaces */
+#define ALGORITHM 0x2b, 0x0e, 0x03, 0x02
+#define X500 0x55
+#define X520_ATTRIBUTE_TYPE X500, 0x04
+#define X500_ALG X500, 0x08
+#define X500_ALG_ENCRYPTION X500_ALG, 0x01
+
+/** X.509 v3 Extension OID
+ ** {joint-iso-ccitt (2) ds(5) 29}
+ **/
+#define ID_CE_OID X500, 0x1d
+
+#define RFC1274_ATTR_TYPE 0x09, 0x92, 0x26, 0x89, 0x93, 0xf2, 0x2c, 0x64, 0x1
+/* #define RFC2247_ATTR_TYPE 0x09, 0x92, 0x26, 0xf5, 0x98, 0x1e, 0x64, 0x1 this is WRONG! */
+
+/* PKCS #12 name spaces */
+#define PKCS12_MODE_IDS PKCS12, 0x01
+#define PKCS12_ESPVK_IDS PKCS12, 0x02
+#define PKCS12_BAG_IDS PKCS12, 0x03
+#define PKCS12_CERT_BAG_IDS PKCS12, 0x04
+#define PKCS12_OIDS PKCS12, 0x05
+#define PKCS12_PBE_IDS PKCS12_OIDS, 0x01
+#define PKCS12_ENVELOPING_IDS PKCS12_OIDS, 0x02
+#define PKCS12_SIGNATURE_IDS PKCS12_OIDS, 0x03
+#define PKCS12_V2_PBE_IDS PKCS12, 0x01
+#define PKCS9_CERT_TYPES PKCS9, 0x16
+#define PKCS9_CRL_TYPES PKCS9, 0x17
+#define PKCS9_SMIME_IDS PKCS9, 0x10
+#define PKCS9_SMIME_ATTRS PKCS9_SMIME_IDS, 2
+#define PKCS9_SMIME_ALGS PKCS9_SMIME_IDS, 3
+#define PKCS12_VERSION1 PKCS12, 0x0a
+#define PKCS12_V1_BAG_IDS PKCS12_VERSION1, 1
+
+/* for DSA algorithm */
+/* { iso(1) member-body(2) us(840) x9-57(10040) x9algorithm(4) } */
+#define ANSI_X9_ALGORITHM 0x2a, 0x86, 0x48, 0xce, 0x38, 0x4
+
+/* for DH algorithm */
+/* { iso(1) member-body(2) us(840) x9-57(10046) number-type(2) } */
+/* need real OID person to look at this, copied the above line
+ * and added 6 to second to last value (and changed '4' to '2' */
+#define ANSI_X942_ALGORITHM 0x2a, 0x86, 0x48, 0xce, 0x3e, 0x2
+
+#define VERISIGN 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x45
+
+#define PKIX 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07
+#define PKIX_CERT_EXTENSIONS PKIX, 1
+#define PKIX_POLICY_QUALIFIERS PKIX, 2
+#define PKIX_KEY_USAGE PKIX, 3
+#define PKIX_ACCESS_DESCRIPTION PKIX, 0x30
+#define PKIX_OCSP PKIX_ACCESS_DESCRIPTION, 1
+#define PKIX_CA_ISSUERS PKIX_ACCESS_DESCRIPTION, 2
+
+#define PKIX_ID_PKIP PKIX, 5
+#define PKIX_ID_REGCTRL PKIX_ID_PKIP, 1
+#define PKIX_ID_REGINFO PKIX_ID_PKIP, 2
+
+/* Microsoft Object ID space */
+/* { 1.3.6.1.4.1.311 } */
+#define MICROSOFT_OID 0x2b, 0x6, 0x1, 0x4, 0x1, 0x82, 0x37
+
+#define CERTICOM_OID 0x2b, 0x81, 0x04
+#define SECG_OID CERTICOM_OID, 0x00
+
+#define ANSI_X962_OID 0x2a, 0x86, 0x48, 0xce, 0x3d
+#define ANSI_X962_CURVE_OID ANSI_X962_OID, 0x03
+#define ANSI_X962_GF2m_OID ANSI_X962_CURVE_OID, 0x00
+#define ANSI_X962_GFp_OID ANSI_X962_CURVE_OID, 0x01
+#define ANSI_X962_SIGNATURE_OID ANSI_X962_OID, 0x04
+#define ANSI_X962_SPECIFY_OID ANSI_X962_SIGNATURE_OID, 0x03
+
+/* for Camellia: iso(1) member-body(2) jisc(392)
+ * mitsubishi(200011) isl(61) security(1) algorithm(1)
+ */
+#define MITSUBISHI_ALG 0x2a,0x83,0x08,0x8c,0x9a,0x4b,0x3d,0x01,0x01
+#define CAMELLIA_ENCRYPT_OID MITSUBISHI_ALG,1
+#define CAMELLIA_WRAP_OID MITSUBISHI_ALG,3
+
+#define CONST_OID static const unsigned char
+
+CONST_OID md2[] = { DIGEST, 0x02 };
+CONST_OID md4[] = { DIGEST, 0x04 };
+CONST_OID md5[] = { DIGEST, 0x05 };
+CONST_OID hmac_sha1[] = { DIGEST, 7 };
+CONST_OID hmac_sha224[] = { DIGEST, 8 };
+CONST_OID hmac_sha256[] = { DIGEST, 9 };
+CONST_OID hmac_sha384[] = { DIGEST, 10 };
+CONST_OID hmac_sha512[] = { DIGEST, 11 };
+
+CONST_OID rc2cbc[] = { CIPHER, 0x02 };
+CONST_OID rc4[] = { CIPHER, 0x04 };
+CONST_OID desede3cbc[] = { CIPHER, 0x07 };
+CONST_OID rc5cbcpad[] = { CIPHER, 0x09 };
+
+CONST_OID desecb[] = { ALGORITHM, 0x06 };
+CONST_OID descbc[] = { ALGORITHM, 0x07 };
+CONST_OID desofb[] = { ALGORITHM, 0x08 };
+CONST_OID descfb[] = { ALGORITHM, 0x09 };
+CONST_OID desmac[] = { ALGORITHM, 0x0a };
+CONST_OID sdn702DSASignature[] = { ALGORITHM, 0x0c };
+CONST_OID isoSHAWithRSASignature[] = { ALGORITHM, 0x0f };
+CONST_OID desede[] = { ALGORITHM, 0x11 };
+CONST_OID sha1[] = { ALGORITHM, 0x1a };
+CONST_OID bogusDSASignaturewithSHA1Digest[] = { ALGORITHM, 0x1b };
+CONST_OID isoSHA1WithRSASignature[] = { ALGORITHM, 0x1d };
+
+CONST_OID pkcs1RSAEncryption[] = { PKCS1, 0x01 };
+CONST_OID pkcs1MD2WithRSAEncryption[] = { PKCS1, 0x02 };
+CONST_OID pkcs1MD4WithRSAEncryption[] = { PKCS1, 0x03 };
+CONST_OID pkcs1MD5WithRSAEncryption[] = { PKCS1, 0x04 };
+CONST_OID pkcs1SHA1WithRSAEncryption[] = { PKCS1, 0x05 };
+CONST_OID pkcs1SHA256WithRSAEncryption[] = { PKCS1, 11 };
+CONST_OID pkcs1SHA384WithRSAEncryption[] = { PKCS1, 12 };
+CONST_OID pkcs1SHA512WithRSAEncryption[] = { PKCS1, 13 };
+
+CONST_OID pkcs5PbeWithMD2AndDEScbc[] = { PKCS5, 0x01 };
+CONST_OID pkcs5PbeWithMD5AndDEScbc[] = { PKCS5, 0x03 };
+CONST_OID pkcs5PbeWithSha1AndDEScbc[] = { PKCS5, 0x0a };
+CONST_OID pkcs5Pbkdf2[] = { PKCS5, 12 };
+CONST_OID pkcs5Pbes2[] = { PKCS5, 13 };
+CONST_OID pkcs5Pbmac1[] = { PKCS5, 14 };
+
+CONST_OID pkcs7[] = { PKCS7 };
+CONST_OID pkcs7Data[] = { PKCS7, 0x01 };
+CONST_OID pkcs7SignedData[] = { PKCS7, 0x02 };
+CONST_OID pkcs7EnvelopedData[] = { PKCS7, 0x03 };
+CONST_OID pkcs7SignedEnvelopedData[] = { PKCS7, 0x04 };
+CONST_OID pkcs7DigestedData[] = { PKCS7, 0x05 };
+CONST_OID pkcs7EncryptedData[] = { PKCS7, 0x06 };
+
+CONST_OID pkcs9EmailAddress[] = { PKCS9, 0x01 };
+CONST_OID pkcs9UnstructuredName[] = { PKCS9, 0x02 };
+CONST_OID pkcs9ContentType[] = { PKCS9, 0x03 };
+CONST_OID pkcs9MessageDigest[] = { PKCS9, 0x04 };
+CONST_OID pkcs9SigningTime[] = { PKCS9, 0x05 };
+CONST_OID pkcs9CounterSignature[] = { PKCS9, 0x06 };
+CONST_OID pkcs9ChallengePassword[] = { PKCS9, 0x07 };
+CONST_OID pkcs9UnstructuredAddress[] = { PKCS9, 0x08 };
+CONST_OID pkcs9ExtendedCertificateAttributes[] = { PKCS9, 0x09 };
+CONST_OID pkcs9ExtensionRequest[] = { PKCS9, 14 };
+CONST_OID pkcs9SMIMECapabilities[] = { PKCS9, 15 };
+CONST_OID pkcs9FriendlyName[] = { PKCS9, 20 };
+CONST_OID pkcs9LocalKeyID[] = { PKCS9, 21 };
+
+CONST_OID pkcs9X509Certificate[] = { PKCS9_CERT_TYPES, 1 };
+CONST_OID pkcs9SDSICertificate[] = { PKCS9_CERT_TYPES, 2 };
+CONST_OID pkcs9X509CRL[] = { PKCS9_CRL_TYPES, 1 };
+
+/* RFC2630 (CMS) OIDs */
+CONST_OID cmsESDH[] = { PKCS9_SMIME_ALGS, 5 };
+CONST_OID cms3DESwrap[] = { PKCS9_SMIME_ALGS, 6 };
+CONST_OID cmsRC2wrap[] = { PKCS9_SMIME_ALGS, 7 };
+
+/* RFC2633 SMIME message attributes */
+CONST_OID smimeEncryptionKeyPreference[] = { PKCS9_SMIME_ATTRS, 11 };
+CONST_OID ms_smimeEncryptionKeyPreference[] = { MICROSOFT_OID, 0x10, 0x4 };
+
+CONST_OID x520CommonName[] = { X520_ATTRIBUTE_TYPE, 3 };
+CONST_OID x520SurName[] = { X520_ATTRIBUTE_TYPE, 4 };
+CONST_OID x520SerialNumber[] = { X520_ATTRIBUTE_TYPE, 5 };
+CONST_OID x520CountryName[] = { X520_ATTRIBUTE_TYPE, 6 };
+CONST_OID x520LocalityName[] = { X520_ATTRIBUTE_TYPE, 7 };
+CONST_OID x520StateOrProvinceName[] = { X520_ATTRIBUTE_TYPE, 8 };
+CONST_OID x520StreetAddress[] = { X520_ATTRIBUTE_TYPE, 9 };
+CONST_OID x520OrgName[] = { X520_ATTRIBUTE_TYPE, 10 };
+CONST_OID x520OrgUnitName[] = { X520_ATTRIBUTE_TYPE, 11 };
+CONST_OID x520Title[] = { X520_ATTRIBUTE_TYPE, 12 };
+CONST_OID x520PostalAddress[] = { X520_ATTRIBUTE_TYPE, 16 };
+CONST_OID x520PostalCode[] = { X520_ATTRIBUTE_TYPE, 17 };
+CONST_OID x520PostOfficeBox[] = { X520_ATTRIBUTE_TYPE, 18 };
+CONST_OID x520GivenName[] = { X520_ATTRIBUTE_TYPE, 42 };
+CONST_OID x520Initials[] = { X520_ATTRIBUTE_TYPE, 43 };
+CONST_OID x520GenerationQualifier[] = { X520_ATTRIBUTE_TYPE, 44 };
+CONST_OID x520DnQualifier[] = { X520_ATTRIBUTE_TYPE, 46 };
+CONST_OID x520HouseIdentifier[] = { X520_ATTRIBUTE_TYPE, 51 };
+CONST_OID x520Pseudonym[] = { X520_ATTRIBUTE_TYPE, 65 };
+
+CONST_OID nsTypeGIF[] = { NETSCAPE_DATA_TYPE, 0x01 };
+CONST_OID nsTypeJPEG[] = { NETSCAPE_DATA_TYPE, 0x02 };
+CONST_OID nsTypeURL[] = { NETSCAPE_DATA_TYPE, 0x03 };
+CONST_OID nsTypeHTML[] = { NETSCAPE_DATA_TYPE, 0x04 };
+CONST_OID nsTypeCertSeq[] = { NETSCAPE_DATA_TYPE, 0x05 };
+
+CONST_OID missiCertKEADSSOld[] = { MISSI_OLD_KEA_DSS };
+CONST_OID missiCertDSSOld[] = { MISSI_OLD_DSS };
+CONST_OID missiCertKEADSS[] = { MISSI_KEA_DSS };
+CONST_OID missiCertDSS[] = { MISSI_DSS };
+CONST_OID missiCertKEA[] = { MISSI_KEA };
+CONST_OID missiCertAltKEA[] = { MISSI_ALT_KEA };
+CONST_OID x500RSAEncryption[] = { X500_ALG_ENCRYPTION, 0x01 };
+
+/* added for alg 1485 */
+CONST_OID rfc1274Uid[] = { RFC1274_ATTR_TYPE, 1 };
+CONST_OID rfc1274Mail[] = { RFC1274_ATTR_TYPE, 3 };
+CONST_OID rfc2247DomainComponent[] = { RFC1274_ATTR_TYPE, 25 };
+
+/* Netscape private certificate extensions */
+CONST_OID nsCertExtNetscapeOK[] = { NS_CERT_EXT, 1 };
+CONST_OID nsCertExtIssuerLogo[] = { NS_CERT_EXT, 2 };
+CONST_OID nsCertExtSubjectLogo[] = { NS_CERT_EXT, 3 };
+CONST_OID nsExtCertType[] = { NETSCAPE_CERT_EXT, 0x01 };
+CONST_OID nsExtBaseURL[] = { NETSCAPE_CERT_EXT, 0x02 };
+CONST_OID nsExtRevocationURL[] = { NETSCAPE_CERT_EXT, 0x03 };
+CONST_OID nsExtCARevocationURL[] = { NETSCAPE_CERT_EXT, 0x04 };
+CONST_OID nsExtCACRLURL[] = { NETSCAPE_CERT_EXT, 0x05 };
+CONST_OID nsExtCACertURL[] = { NETSCAPE_CERT_EXT, 0x06 };
+CONST_OID nsExtCertRenewalURL[] = { NETSCAPE_CERT_EXT, 0x07 };
+CONST_OID nsExtCAPolicyURL[] = { NETSCAPE_CERT_EXT, 0x08 };
+CONST_OID nsExtHomepageURL[] = { NETSCAPE_CERT_EXT, 0x09 };
+CONST_OID nsExtEntityLogo[] = { NETSCAPE_CERT_EXT, 0x0a };
+CONST_OID nsExtUserPicture[] = { NETSCAPE_CERT_EXT, 0x0b };
+CONST_OID nsExtSSLServerName[] = { NETSCAPE_CERT_EXT, 0x0c };
+CONST_OID nsExtComment[] = { NETSCAPE_CERT_EXT, 0x0d };
+
+/* the following 2 extensions are defined for and used by Cartman(NSM) */
+CONST_OID nsExtLostPasswordURL[] = { NETSCAPE_CERT_EXT, 0x0e };
+CONST_OID nsExtCertRenewalTime[] = { NETSCAPE_CERT_EXT, 0x0f };
+
+CONST_OID nsExtAIACertRenewal[] = { NETSCAPE_CERT_EXT_AIA, 0x01 };
+CONST_OID nsExtCertScopeOfUse[] = { NETSCAPE_CERT_EXT, 0x11 };
+/* Reserved Netscape (2 16 840 1 113730 1 18) = { NETSCAPE_CERT_EXT, 0x12 }; */
+
+/* Netscape policy values */
+CONST_OID nsKeyUsageGovtApproved[] = { NETSCAPE_POLICY, 0x01 };
+
+/* Netscape other name types */
+CONST_OID netscapeNickname[] = { NETSCAPE_NAME_COMPONENTS, 0x01 };
+CONST_OID netscapeAOLScreenname[] = { NETSCAPE_NAME_COMPONENTS, 0x02 };
+
+/* OIDs needed for cert server */
+CONST_OID netscapeRecoveryRequest[] = { NETSCAPE_CERT_SERVER_CRMF, 0x01 };
+
+
+/* Standard x.509 v3 Certificate & CRL Extensions */
+CONST_OID x509SubjectDirectoryAttr[] = { ID_CE_OID, 9 };
+CONST_OID x509SubjectKeyID[] = { ID_CE_OID, 14 };
+CONST_OID x509KeyUsage[] = { ID_CE_OID, 15 };
+CONST_OID x509PrivateKeyUsagePeriod[] = { ID_CE_OID, 16 };
+CONST_OID x509SubjectAltName[] = { ID_CE_OID, 17 };
+CONST_OID x509IssuerAltName[] = { ID_CE_OID, 18 };
+CONST_OID x509BasicConstraints[] = { ID_CE_OID, 19 };
+CONST_OID x509CRLNumber[] = { ID_CE_OID, 20 };
+CONST_OID x509ReasonCode[] = { ID_CE_OID, 21 };
+CONST_OID x509HoldInstructionCode[] = { ID_CE_OID, 23 };
+CONST_OID x509InvalidDate[] = { ID_CE_OID, 24 };
+CONST_OID x509DeltaCRLIndicator[] = { ID_CE_OID, 27 };
+CONST_OID x509IssuingDistributionPoint[] = { ID_CE_OID, 28 };
+CONST_OID x509CertIssuer[] = { ID_CE_OID, 29 };
+CONST_OID x509NameConstraints[] = { ID_CE_OID, 30 };
+CONST_OID x509CRLDistPoints[] = { ID_CE_OID, 31 };
+CONST_OID x509CertificatePolicies[] = { ID_CE_OID, 32 };
+CONST_OID x509PolicyMappings[] = { ID_CE_OID, 33 };
+CONST_OID x509AuthKeyID[] = { ID_CE_OID, 35 };
+CONST_OID x509PolicyConstraints[] = { ID_CE_OID, 36 };
+CONST_OID x509ExtKeyUsage[] = { ID_CE_OID, 37 };
+CONST_OID x509FreshestCRL[] = { ID_CE_OID, 46 };
+CONST_OID x509InhibitAnyPolicy[] = { ID_CE_OID, 54 };
+
+CONST_OID x509AuthInfoAccess[] = { PKIX_CERT_EXTENSIONS, 1 };
+CONST_OID x509SubjectInfoAccess[] = { PKIX_CERT_EXTENSIONS, 11 };
+
+CONST_OID x509SIATimeStamping[] = {PKIX_ACCESS_DESCRIPTION, 0x03};
+CONST_OID x509SIACaRepository[] = {PKIX_ACCESS_DESCRIPTION, 0x05};
+
+/* pkcs 12 additions */
+CONST_OID pkcs12[] = { PKCS12 };
+CONST_OID pkcs12ModeIDs[] = { PKCS12_MODE_IDS };
+CONST_OID pkcs12ESPVKIDs[] = { PKCS12_ESPVK_IDS };
+CONST_OID pkcs12BagIDs[] = { PKCS12_BAG_IDS };
+CONST_OID pkcs12CertBagIDs[] = { PKCS12_CERT_BAG_IDS };
+CONST_OID pkcs12OIDs[] = { PKCS12_OIDS };
+CONST_OID pkcs12PBEIDs[] = { PKCS12_PBE_IDS };
+CONST_OID pkcs12EnvelopingIDs[] = { PKCS12_ENVELOPING_IDS };
+CONST_OID pkcs12SignatureIDs[] = { PKCS12_SIGNATURE_IDS };
+CONST_OID pkcs12PKCS8KeyShrouding[] = { PKCS12_ESPVK_IDS, 0x01 };
+CONST_OID pkcs12KeyBagID[] = { PKCS12_BAG_IDS, 0x01 };
+CONST_OID pkcs12CertAndCRLBagID[] = { PKCS12_BAG_IDS, 0x02 };
+CONST_OID pkcs12SecretBagID[] = { PKCS12_BAG_IDS, 0x03 };
+CONST_OID pkcs12X509CertCRLBag[] = { PKCS12_CERT_BAG_IDS, 0x01 };
+CONST_OID pkcs12SDSICertBag[] = { PKCS12_CERT_BAG_IDS, 0x02 };
+CONST_OID pkcs12PBEWithSha1And128BitRC4[] = { PKCS12_PBE_IDS, 0x01 };
+CONST_OID pkcs12PBEWithSha1And40BitRC4[] = { PKCS12_PBE_IDS, 0x02 };
+CONST_OID pkcs12PBEWithSha1AndTripleDESCBC[] = { PKCS12_PBE_IDS, 0x03 };
+CONST_OID pkcs12PBEWithSha1And128BitRC2CBC[] = { PKCS12_PBE_IDS, 0x04 };
+CONST_OID pkcs12PBEWithSha1And40BitRC2CBC[] = { PKCS12_PBE_IDS, 0x05 };
+CONST_OID pkcs12RSAEncryptionWith128BitRC4[] = { PKCS12_ENVELOPING_IDS, 0x01 };
+CONST_OID pkcs12RSAEncryptionWith40BitRC4[] = { PKCS12_ENVELOPING_IDS, 0x02 };
+CONST_OID pkcs12RSAEncryptionWithTripleDES[] = { PKCS12_ENVELOPING_IDS, 0x03 };
+CONST_OID pkcs12RSASignatureWithSHA1Digest[] = { PKCS12_SIGNATURE_IDS, 0x01 };
+
+/* pkcs 12 version 1.0 ids */
+CONST_OID pkcs12V2PBEWithSha1And128BitRC4[] = { PKCS12_V2_PBE_IDS, 0x01 };
+CONST_OID pkcs12V2PBEWithSha1And40BitRC4[] = { PKCS12_V2_PBE_IDS, 0x02 };
+CONST_OID pkcs12V2PBEWithSha1And3KeyTripleDEScbc[]= { PKCS12_V2_PBE_IDS, 0x03 };
+CONST_OID pkcs12V2PBEWithSha1And2KeyTripleDEScbc[]= { PKCS12_V2_PBE_IDS, 0x04 };
+CONST_OID pkcs12V2PBEWithSha1And128BitRC2cbc[] = { PKCS12_V2_PBE_IDS, 0x05 };
+CONST_OID pkcs12V2PBEWithSha1And40BitRC2cbc[] = { PKCS12_V2_PBE_IDS, 0x06 };
+
+CONST_OID pkcs12SafeContentsID[] = { PKCS12_BAG_IDS, 0x04 };
+CONST_OID pkcs12PKCS8ShroudedKeyBagID[] = { PKCS12_BAG_IDS, 0x05 };
+
+CONST_OID pkcs12V1KeyBag[] = { PKCS12_V1_BAG_IDS, 0x01 };
+CONST_OID pkcs12V1PKCS8ShroudedKeyBag[] = { PKCS12_V1_BAG_IDS, 0x02 };
+CONST_OID pkcs12V1CertBag[] = { PKCS12_V1_BAG_IDS, 0x03 };
+CONST_OID pkcs12V1CRLBag[] = { PKCS12_V1_BAG_IDS, 0x04 };
+CONST_OID pkcs12V1SecretBag[] = { PKCS12_V1_BAG_IDS, 0x05 };
+CONST_OID pkcs12V1SafeContentsBag[] = { PKCS12_V1_BAG_IDS, 0x06 };
+
+/* The following encoding is INCORRECT, but correcting it would create a
+ * duplicate OID in the table. So, we will leave it alone.
+ */
+CONST_OID pkcs12KeyUsageAttr[] = { 2, 5, 29, 15 };
+
+CONST_OID ansix9DSASignature[] = { ANSI_X9_ALGORITHM, 0x01 };
+CONST_OID ansix9DSASignaturewithSHA1Digest[] = { ANSI_X9_ALGORITHM, 0x03 };
+
+/* verisign OIDs */
+CONST_OID verisignUserNotices[] = { VERISIGN, 1, 7, 1, 1 };
+
+/* pkix OIDs */
+CONST_OID pkixCPSPointerQualifier[] = { PKIX_POLICY_QUALIFIERS, 1 };
+CONST_OID pkixUserNoticeQualifier[] = { PKIX_POLICY_QUALIFIERS, 2 };
+
+CONST_OID pkixOCSP[] = { PKIX_OCSP };
+CONST_OID pkixOCSPBasicResponse[] = { PKIX_OCSP, 1 };
+CONST_OID pkixOCSPNonce[] = { PKIX_OCSP, 2 };
+CONST_OID pkixOCSPCRL[] = { PKIX_OCSP, 3 };
+CONST_OID pkixOCSPResponse[] = { PKIX_OCSP, 4 };
+CONST_OID pkixOCSPNoCheck[] = { PKIX_OCSP, 5 };
+CONST_OID pkixOCSPArchiveCutoff[] = { PKIX_OCSP, 6 };
+CONST_OID pkixOCSPServiceLocator[] = { PKIX_OCSP, 7 };
+
+CONST_OID pkixCAIssuers[] = { PKIX_CA_ISSUERS };
+
+CONST_OID pkixRegCtrlRegToken[] = { PKIX_ID_REGCTRL, 1};
+CONST_OID pkixRegCtrlAuthenticator[] = { PKIX_ID_REGCTRL, 2};
+CONST_OID pkixRegCtrlPKIPubInfo[] = { PKIX_ID_REGCTRL, 3};
+CONST_OID pkixRegCtrlPKIArchOptions[] = { PKIX_ID_REGCTRL, 4};
+CONST_OID pkixRegCtrlOldCertID[] = { PKIX_ID_REGCTRL, 5};
+CONST_OID pkixRegCtrlProtEncKey[] = { PKIX_ID_REGCTRL, 6};
+CONST_OID pkixRegInfoUTF8Pairs[] = { PKIX_ID_REGINFO, 1};
+CONST_OID pkixRegInfoCertReq[] = { PKIX_ID_REGINFO, 2};
+
+CONST_OID pkixExtendedKeyUsageServerAuth[] = { PKIX_KEY_USAGE, 1 };
+CONST_OID pkixExtendedKeyUsageClientAuth[] = { PKIX_KEY_USAGE, 2 };
+CONST_OID pkixExtendedKeyUsageCodeSign[] = { PKIX_KEY_USAGE, 3 };
+CONST_OID pkixExtendedKeyUsageEMailProtect[] = { PKIX_KEY_USAGE, 4 };
+CONST_OID pkixExtendedKeyUsageTimeStamp[] = { PKIX_KEY_USAGE, 8 };
+CONST_OID pkixOCSPResponderExtendedKeyUsage[] = { PKIX_KEY_USAGE, 9 };
+
+/* OIDs for Netscape defined algorithms */
+CONST_OID netscapeSMimeKEA[] = { NETSCAPE_ALGS, 0x01 };
+
+/* Fortezza algorithm OIDs */
+CONST_OID skipjackCBC[] = { FORTEZZA_ALG, 0x04 };
+CONST_OID dhPublicKey[] = { ANSI_X942_ALGORITHM, 0x1 };
+
+CONST_OID aes128_ECB[] = { AES, 1 };
+CONST_OID aes128_CBC[] = { AES, 2 };
+#ifdef DEFINE_ALL_AES_CIPHERS
+CONST_OID aes128_OFB[] = { AES, 3 };
+CONST_OID aes128_CFB[] = { AES, 4 };
+#endif
+CONST_OID aes128_KEY_WRAP[] = { AES, 5 };
+
+CONST_OID aes192_ECB[] = { AES, 21 };
+CONST_OID aes192_CBC[] = { AES, 22 };
+#ifdef DEFINE_ALL_AES_CIPHERS
+CONST_OID aes192_OFB[] = { AES, 23 };
+CONST_OID aes192_CFB[] = { AES, 24 };
+#endif
+CONST_OID aes192_KEY_WRAP[] = { AES, 25 };
+
+CONST_OID aes256_ECB[] = { AES, 41 };
+CONST_OID aes256_CBC[] = { AES, 42 };
+#ifdef DEFINE_ALL_AES_CIPHERS
+CONST_OID aes256_OFB[] = { AES, 43 };
+CONST_OID aes256_CFB[] = { AES, 44 };
+#endif
+CONST_OID aes256_KEY_WRAP[] = { AES, 45 };
+
+CONST_OID camellia128_CBC[] = { CAMELLIA_ENCRYPT_OID, 2};
+CONST_OID camellia192_CBC[] = { CAMELLIA_ENCRYPT_OID, 3};
+CONST_OID camellia256_CBC[] = { CAMELLIA_ENCRYPT_OID, 4};
+CONST_OID camellia128_KEY_WRAP[] = { CAMELLIA_WRAP_OID, 2};
+CONST_OID camellia192_KEY_WRAP[] = { CAMELLIA_WRAP_OID, 3};
+CONST_OID camellia256_KEY_WRAP[] = { CAMELLIA_WRAP_OID, 4};
+
+CONST_OID sha256[] = { SHAXXX, 1 };
+CONST_OID sha384[] = { SHAXXX, 2 };
+CONST_OID sha512[] = { SHAXXX, 3 };
+
+CONST_OID ansix962ECPublicKey[] = { ANSI_X962_OID, 0x02, 0x01 };
+CONST_OID ansix962SignaturewithSHA1Digest[] = { ANSI_X962_SIGNATURE_OID, 0x01 };
+CONST_OID ansix962SignatureRecommended[] = { ANSI_X962_SIGNATURE_OID, 0x02 };
+CONST_OID ansix962SignatureSpecified[] = { ANSI_X962_SPECIFY_OID };
+CONST_OID ansix962SignaturewithSHA224Digest[] = { ANSI_X962_SPECIFY_OID, 0x01 };
+CONST_OID ansix962SignaturewithSHA256Digest[] = { ANSI_X962_SPECIFY_OID, 0x02 };
+CONST_OID ansix962SignaturewithSHA384Digest[] = { ANSI_X962_SPECIFY_OID, 0x03 };
+CONST_OID ansix962SignaturewithSHA512Digest[] = { ANSI_X962_SPECIFY_OID, 0x04 };
+
+/* ANSI X9.62 prime curve OIDs */
+/* NOTE: prime192v1 is the same as secp192r1, prime256v1 is the
+ * same as secp256r1
+ */
+CONST_OID ansiX962prime192v1[] = { ANSI_X962_GFp_OID, 0x01 };
+CONST_OID ansiX962prime192v2[] = { ANSI_X962_GFp_OID, 0x02 };
+CONST_OID ansiX962prime192v3[] = { ANSI_X962_GFp_OID, 0x03 };
+CONST_OID ansiX962prime239v1[] = { ANSI_X962_GFp_OID, 0x04 };
+CONST_OID ansiX962prime239v2[] = { ANSI_X962_GFp_OID, 0x05 };
+CONST_OID ansiX962prime239v3[] = { ANSI_X962_GFp_OID, 0x06 };
+CONST_OID ansiX962prime256v1[] = { ANSI_X962_GFp_OID, 0x07 };
+
+/* SECG prime curve OIDs */
+CONST_OID secgECsecp112r1[] = { SECG_OID, 0x06 };
+CONST_OID secgECsecp112r2[] = { SECG_OID, 0x07 };
+CONST_OID secgECsecp128r1[] = { SECG_OID, 0x1c };
+CONST_OID secgECsecp128r2[] = { SECG_OID, 0x1d };
+CONST_OID secgECsecp160k1[] = { SECG_OID, 0x09 };
+CONST_OID secgECsecp160r1[] = { SECG_OID, 0x08 };
+CONST_OID secgECsecp160r2[] = { SECG_OID, 0x1e };
+CONST_OID secgECsecp192k1[] = { SECG_OID, 0x1f };
+CONST_OID secgECsecp224k1[] = { SECG_OID, 0x20 };
+CONST_OID secgECsecp224r1[] = { SECG_OID, 0x21 };
+CONST_OID secgECsecp256k1[] = { SECG_OID, 0x0a };
+CONST_OID secgECsecp384r1[] = { SECG_OID, 0x22 };
+CONST_OID secgECsecp521r1[] = { SECG_OID, 0x23 };
+
+/* ANSI X9.62 characteristic two curve OIDs */
+CONST_OID ansiX962c2pnb163v1[] = { ANSI_X962_GF2m_OID, 0x01 };
+CONST_OID ansiX962c2pnb163v2[] = { ANSI_X962_GF2m_OID, 0x02 };
+CONST_OID ansiX962c2pnb163v3[] = { ANSI_X962_GF2m_OID, 0x03 };
+CONST_OID ansiX962c2pnb176v1[] = { ANSI_X962_GF2m_OID, 0x04 };
+CONST_OID ansiX962c2tnb191v1[] = { ANSI_X962_GF2m_OID, 0x05 };
+CONST_OID ansiX962c2tnb191v2[] = { ANSI_X962_GF2m_OID, 0x06 };
+CONST_OID ansiX962c2tnb191v3[] = { ANSI_X962_GF2m_OID, 0x07 };
+CONST_OID ansiX962c2onb191v4[] = { ANSI_X962_GF2m_OID, 0x08 };
+CONST_OID ansiX962c2onb191v5[] = { ANSI_X962_GF2m_OID, 0x09 };
+CONST_OID ansiX962c2pnb208w1[] = { ANSI_X962_GF2m_OID, 0x0a };
+CONST_OID ansiX962c2tnb239v1[] = { ANSI_X962_GF2m_OID, 0x0b };
+CONST_OID ansiX962c2tnb239v2[] = { ANSI_X962_GF2m_OID, 0x0c };
+CONST_OID ansiX962c2tnb239v3[] = { ANSI_X962_GF2m_OID, 0x0d };
+CONST_OID ansiX962c2onb239v4[] = { ANSI_X962_GF2m_OID, 0x0e };
+CONST_OID ansiX962c2onb239v5[] = { ANSI_X962_GF2m_OID, 0x0f };
+CONST_OID ansiX962c2pnb272w1[] = { ANSI_X962_GF2m_OID, 0x10 };
+CONST_OID ansiX962c2pnb304w1[] = { ANSI_X962_GF2m_OID, 0x11 };
+CONST_OID ansiX962c2tnb359v1[] = { ANSI_X962_GF2m_OID, 0x12 };
+CONST_OID ansiX962c2pnb368w1[] = { ANSI_X962_GF2m_OID, 0x13 };
+CONST_OID ansiX962c2tnb431r1[] = { ANSI_X962_GF2m_OID, 0x14 };
+
+/* SECG characterisitic two curve OIDs */
+CONST_OID secgECsect113r1[] = {SECG_OID, 0x04 };
+CONST_OID secgECsect113r2[] = {SECG_OID, 0x05 };
+CONST_OID secgECsect131r1[] = {SECG_OID, 0x16 };
+CONST_OID secgECsect131r2[] = {SECG_OID, 0x17 };
+CONST_OID secgECsect163k1[] = {SECG_OID, 0x01 };
+CONST_OID secgECsect163r1[] = {SECG_OID, 0x02 };
+CONST_OID secgECsect163r2[] = {SECG_OID, 0x0f };
+CONST_OID secgECsect193r1[] = {SECG_OID, 0x18 };
+CONST_OID secgECsect193r2[] = {SECG_OID, 0x19 };
+CONST_OID secgECsect233k1[] = {SECG_OID, 0x1a };
+CONST_OID secgECsect233r1[] = {SECG_OID, 0x1b };
+CONST_OID secgECsect239k1[] = {SECG_OID, 0x03 };
+CONST_OID secgECsect283k1[] = {SECG_OID, 0x10 };
+CONST_OID secgECsect283r1[] = {SECG_OID, 0x11 };
+CONST_OID secgECsect409k1[] = {SECG_OID, 0x24 };
+CONST_OID secgECsect409r1[] = {SECG_OID, 0x25 };
+CONST_OID secgECsect571k1[] = {SECG_OID, 0x26 };
+CONST_OID secgECsect571r1[] = {SECG_OID, 0x27 };
+
+#define OI(x) { siDEROID, (unsigned char *)x, sizeof x }
+#ifndef SECOID_NO_STRINGS
+#define OD(oid,tag,desc,mech,ext) { OI(oid), tag, desc, mech, ext }
+#else
+#define OD(oid,tag,desc,mech,ext) { OI(oid), tag, 0, mech, ext }
+#endif
+
+#if defined(NSS_ALLOW_UNSUPPORTED_CRITICAL)
+#define FAKE_SUPPORTED_CERT_EXTENSION SUPPORTED_CERT_EXTENSION
+#else
+#define FAKE_SUPPORTED_CERT_EXTENSION UNSUPPORTED_CERT_EXTENSION
+#endif
+
+/*
+ * NOTE: the order of these entries must mach the SECOidTag enum in secoidt.h!
+ */
+const static SECOidData oids[] = {
+ { { siDEROID, NULL, 0 }, SEC_OID_UNKNOWN,
+ "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION },
+ OD( md2, SEC_OID_MD2, "MD2", CKM_MD2, INVALID_CERT_EXTENSION ),
+ OD( md4, SEC_OID_MD4,
+ "MD4", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( md5, SEC_OID_MD5, "MD5", CKM_MD5, INVALID_CERT_EXTENSION ),
+ OD( sha1, SEC_OID_SHA1, "SHA-1", CKM_SHA_1, INVALID_CERT_EXTENSION ),
+ OD( rc2cbc, SEC_OID_RC2_CBC,
+ "RC2-CBC", CKM_RC2_CBC, INVALID_CERT_EXTENSION ),
+ OD( rc4, SEC_OID_RC4, "RC4", CKM_RC4, INVALID_CERT_EXTENSION ),
+ OD( desede3cbc, SEC_OID_DES_EDE3_CBC,
+ "DES-EDE3-CBC", CKM_DES3_CBC, INVALID_CERT_EXTENSION ),
+ OD( rc5cbcpad, SEC_OID_RC5_CBC_PAD,
+ "RC5-CBCPad", CKM_RC5_CBC, INVALID_CERT_EXTENSION ),
+ OD( desecb, SEC_OID_DES_ECB,
+ "DES-ECB", CKM_DES_ECB, INVALID_CERT_EXTENSION ),
+ OD( descbc, SEC_OID_DES_CBC,
+ "DES-CBC", CKM_DES_CBC, INVALID_CERT_EXTENSION ),
+ OD( desofb, SEC_OID_DES_OFB,
+ "DES-OFB", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( descfb, SEC_OID_DES_CFB,
+ "DES-CFB", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( desmac, SEC_OID_DES_MAC,
+ "DES-MAC", CKM_DES_MAC, INVALID_CERT_EXTENSION ),
+ OD( desede, SEC_OID_DES_EDE,
+ "DES-EDE", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( isoSHAWithRSASignature, SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE,
+ "ISO SHA with RSA Signature",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs1RSAEncryption, SEC_OID_PKCS1_RSA_ENCRYPTION,
+ "PKCS #1 RSA Encryption", CKM_RSA_PKCS, INVALID_CERT_EXTENSION ),
+
+ /* the following Signing mechanisms should get new CKM_ values when
+ * values for CKM_RSA_WITH_MDX and CKM_RSA_WITH_SHA_1 get defined in
+ * PKCS #11.
+ */
+ OD( pkcs1MD2WithRSAEncryption, SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION,
+ "PKCS #1 MD2 With RSA Encryption", CKM_MD2_RSA_PKCS,
+ INVALID_CERT_EXTENSION ),
+ OD( pkcs1MD4WithRSAEncryption, SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION,
+ "PKCS #1 MD4 With RSA Encryption",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs1MD5WithRSAEncryption, SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION,
+ "PKCS #1 MD5 With RSA Encryption", CKM_MD5_RSA_PKCS,
+ INVALID_CERT_EXTENSION ),
+ OD( pkcs1SHA1WithRSAEncryption, SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION,
+ "PKCS #1 SHA-1 With RSA Encryption", CKM_SHA1_RSA_PKCS,
+ INVALID_CERT_EXTENSION ),
+
+ OD( pkcs5PbeWithMD2AndDEScbc, SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC,
+ "PKCS #5 Password Based Encryption with MD2 and DES CBC",
+ CKM_PBE_MD2_DES_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs5PbeWithMD5AndDEScbc, SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC,
+ "PKCS #5 Password Based Encryption with MD5 and DES CBC",
+ CKM_PBE_MD5_DES_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs5PbeWithSha1AndDEScbc, SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC,
+ "PKCS #5 Password Based Encryption with SHA1 and DES CBC",
+ CKM_NETSCAPE_PBE_SHA1_DES_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs7, SEC_OID_PKCS7,
+ "PKCS #7", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs7Data, SEC_OID_PKCS7_DATA,
+ "PKCS #7 Data", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs7SignedData, SEC_OID_PKCS7_SIGNED_DATA,
+ "PKCS #7 Signed Data", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs7EnvelopedData, SEC_OID_PKCS7_ENVELOPED_DATA,
+ "PKCS #7 Enveloped Data",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs7SignedEnvelopedData, SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA,
+ "PKCS #7 Signed And Enveloped Data",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs7DigestedData, SEC_OID_PKCS7_DIGESTED_DATA,
+ "PKCS #7 Digested Data",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs7EncryptedData, SEC_OID_PKCS7_ENCRYPTED_DATA,
+ "PKCS #7 Encrypted Data",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9EmailAddress, SEC_OID_PKCS9_EMAIL_ADDRESS,
+ "PKCS #9 Email Address",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9UnstructuredName, SEC_OID_PKCS9_UNSTRUCTURED_NAME,
+ "PKCS #9 Unstructured Name",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9ContentType, SEC_OID_PKCS9_CONTENT_TYPE,
+ "PKCS #9 Content Type",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9MessageDigest, SEC_OID_PKCS9_MESSAGE_DIGEST,
+ "PKCS #9 Message Digest",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9SigningTime, SEC_OID_PKCS9_SIGNING_TIME,
+ "PKCS #9 Signing Time",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9CounterSignature, SEC_OID_PKCS9_COUNTER_SIGNATURE,
+ "PKCS #9 Counter Signature",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9ChallengePassword, SEC_OID_PKCS9_CHALLENGE_PASSWORD,
+ "PKCS #9 Challenge Password",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9UnstructuredAddress, SEC_OID_PKCS9_UNSTRUCTURED_ADDRESS,
+ "PKCS #9 Unstructured Address",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9ExtendedCertificateAttributes,
+ SEC_OID_PKCS9_EXTENDED_CERTIFICATE_ATTRIBUTES,
+ "PKCS #9 Extended Certificate Attributes",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9SMIMECapabilities, SEC_OID_PKCS9_SMIME_CAPABILITIES,
+ "PKCS #9 S/MIME Capabilities",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520CommonName, SEC_OID_AVA_COMMON_NAME,
+ "X520 Common Name", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520CountryName, SEC_OID_AVA_COUNTRY_NAME,
+ "X520 Country Name", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520LocalityName, SEC_OID_AVA_LOCALITY,
+ "X520 Locality Name", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520StateOrProvinceName, SEC_OID_AVA_STATE_OR_PROVINCE,
+ "X520 State Or Province Name",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520OrgName, SEC_OID_AVA_ORGANIZATION_NAME,
+ "X520 Organization Name",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520OrgUnitName, SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME,
+ "X520 Organizational Unit Name",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520DnQualifier, SEC_OID_AVA_DN_QUALIFIER,
+ "X520 DN Qualifier", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( rfc2247DomainComponent, SEC_OID_AVA_DC,
+ "RFC 2247 Domain Component",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ OD( nsTypeGIF, SEC_OID_NS_TYPE_GIF,
+ "GIF", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( nsTypeJPEG, SEC_OID_NS_TYPE_JPEG,
+ "JPEG", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( nsTypeURL, SEC_OID_NS_TYPE_URL,
+ "URL", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( nsTypeHTML, SEC_OID_NS_TYPE_HTML,
+ "HTML", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( nsTypeCertSeq, SEC_OID_NS_TYPE_CERT_SEQUENCE,
+ "Certificate Sequence",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( missiCertKEADSSOld, SEC_OID_MISSI_KEA_DSS_OLD,
+ "MISSI KEA and DSS Algorithm (Old)",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( missiCertDSSOld, SEC_OID_MISSI_DSS_OLD,
+ "MISSI DSS Algorithm (Old)",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( missiCertKEADSS, SEC_OID_MISSI_KEA_DSS,
+ "MISSI KEA and DSS Algorithm",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( missiCertDSS, SEC_OID_MISSI_DSS,
+ "MISSI DSS Algorithm",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( missiCertKEA, SEC_OID_MISSI_KEA,
+ "MISSI KEA Algorithm",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( missiCertAltKEA, SEC_OID_MISSI_ALT_KEA,
+ "MISSI Alternate KEA Algorithm",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* Netscape private extensions */
+ OD( nsCertExtNetscapeOK, SEC_OID_NS_CERT_EXT_NETSCAPE_OK,
+ "Netscape says this cert is OK",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( nsCertExtIssuerLogo, SEC_OID_NS_CERT_EXT_ISSUER_LOGO,
+ "Certificate Issuer Logo",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( nsCertExtSubjectLogo, SEC_OID_NS_CERT_EXT_SUBJECT_LOGO,
+ "Certificate Subject Logo",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( nsExtCertType, SEC_OID_NS_CERT_EXT_CERT_TYPE,
+ "Certificate Type",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsExtBaseURL, SEC_OID_NS_CERT_EXT_BASE_URL,
+ "Certificate Extension Base URL",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsExtRevocationURL, SEC_OID_NS_CERT_EXT_REVOCATION_URL,
+ "Certificate Revocation URL",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsExtCARevocationURL, SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL,
+ "Certificate Authority Revocation URL",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsExtCACRLURL, SEC_OID_NS_CERT_EXT_CA_CRL_URL,
+ "Certificate Authority CRL Download URL",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( nsExtCACertURL, SEC_OID_NS_CERT_EXT_CA_CERT_URL,
+ "Certificate Authority Certificate Download URL",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( nsExtCertRenewalURL, SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL,
+ "Certificate Renewal URL",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsExtCAPolicyURL, SEC_OID_NS_CERT_EXT_CA_POLICY_URL,
+ "Certificate Authority Policy URL",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsExtHomepageURL, SEC_OID_NS_CERT_EXT_HOMEPAGE_URL,
+ "Certificate Homepage URL",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( nsExtEntityLogo, SEC_OID_NS_CERT_EXT_ENTITY_LOGO,
+ "Certificate Entity Logo",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( nsExtUserPicture, SEC_OID_NS_CERT_EXT_USER_PICTURE,
+ "Certificate User Picture",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( nsExtSSLServerName, SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME,
+ "Certificate SSL Server Name",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsExtComment, SEC_OID_NS_CERT_EXT_COMMENT,
+ "Certificate Comment",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsExtLostPasswordURL, SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL,
+ "Lost Password URL",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsExtCertRenewalTime, SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME,
+ "Certificate Renewal Time",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( nsKeyUsageGovtApproved, SEC_OID_NS_KEY_USAGE_GOVT_APPROVED,
+ "Strong Crypto Export Approved",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+
+
+ /* x.509 v3 certificate extensions */
+ OD( x509SubjectDirectoryAttr, SEC_OID_X509_SUBJECT_DIRECTORY_ATTR,
+ "Certificate Subject Directory Attributes",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION),
+ OD( x509SubjectKeyID, SEC_OID_X509_SUBJECT_KEY_ID,
+ "Certificate Subject Key ID",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509KeyUsage, SEC_OID_X509_KEY_USAGE,
+ "Certificate Key Usage",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509PrivateKeyUsagePeriod, SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD,
+ "Certificate Private Key Usage Period",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( x509SubjectAltName, SEC_OID_X509_SUBJECT_ALT_NAME,
+ "Certificate Subject Alt Name",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509IssuerAltName, SEC_OID_X509_ISSUER_ALT_NAME,
+ "Certificate Issuer Alt Name",
+ CKM_INVALID_MECHANISM, FAKE_SUPPORTED_CERT_EXTENSION ),
+ OD( x509BasicConstraints, SEC_OID_X509_BASIC_CONSTRAINTS,
+ "Certificate Basic Constraints",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509NameConstraints, SEC_OID_X509_NAME_CONSTRAINTS,
+ "Certificate Name Constraints",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509CRLDistPoints, SEC_OID_X509_CRL_DIST_POINTS,
+ "CRL Distribution Points",
+ CKM_INVALID_MECHANISM, FAKE_SUPPORTED_CERT_EXTENSION ),
+ OD( x509CertificatePolicies, SEC_OID_X509_CERTIFICATE_POLICIES,
+ "Certificate Policies",
+ CKM_INVALID_MECHANISM, FAKE_SUPPORTED_CERT_EXTENSION ),
+ OD( x509PolicyMappings, SEC_OID_X509_POLICY_MAPPINGS,
+ "Certificate Policy Mappings",
+ CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION ),
+ OD( x509PolicyConstraints, SEC_OID_X509_POLICY_CONSTRAINTS,
+ "Certificate Policy Constraints",
+ CKM_INVALID_MECHANISM, FAKE_SUPPORTED_CERT_EXTENSION ),
+ OD( x509AuthKeyID, SEC_OID_X509_AUTH_KEY_ID,
+ "Certificate Authority Key Identifier",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509ExtKeyUsage, SEC_OID_X509_EXT_KEY_USAGE,
+ "Extended Key Usage",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509AuthInfoAccess, SEC_OID_X509_AUTH_INFO_ACCESS,
+ "Authority Information Access",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+
+ /* x.509 v3 CRL extensions */
+ OD( x509CRLNumber, SEC_OID_X509_CRL_NUMBER,
+ "CRL Number", CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509ReasonCode, SEC_OID_X509_REASON_CODE,
+ "CRL reason code", CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( x509InvalidDate, SEC_OID_X509_INVALID_DATE,
+ "Invalid Date", CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+
+ OD( x500RSAEncryption, SEC_OID_X500_RSA_ENCRYPTION,
+ "X500 RSA Encryption", CKM_RSA_X_509, INVALID_CERT_EXTENSION ),
+
+ /* added for alg 1485 */
+ OD( rfc1274Uid, SEC_OID_RFC1274_UID,
+ "RFC1274 User Id", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( rfc1274Mail, SEC_OID_RFC1274_MAIL,
+ "RFC1274 E-mail Address",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* pkcs 12 additions */
+ OD( pkcs12, SEC_OID_PKCS12,
+ "PKCS #12", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12ModeIDs, SEC_OID_PKCS12_MODE_IDS,
+ "PKCS #12 Mode IDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12ESPVKIDs, SEC_OID_PKCS12_ESPVK_IDS,
+ "PKCS #12 ESPVK IDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12BagIDs, SEC_OID_PKCS12_BAG_IDS,
+ "PKCS #12 Bag IDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12CertBagIDs, SEC_OID_PKCS12_CERT_BAG_IDS,
+ "PKCS #12 Cert Bag IDs",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12OIDs, SEC_OID_PKCS12_OIDS,
+ "PKCS #12 OIDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12PBEIDs, SEC_OID_PKCS12_PBE_IDS,
+ "PKCS #12 PBE IDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12SignatureIDs, SEC_OID_PKCS12_SIGNATURE_IDS,
+ "PKCS #12 Signature IDs",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12EnvelopingIDs, SEC_OID_PKCS12_ENVELOPING_IDS,
+ "PKCS #12 Enveloping IDs",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12PKCS8KeyShrouding, SEC_OID_PKCS12_PKCS8_KEY_SHROUDING,
+ "PKCS #12 Key Shrouding",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12KeyBagID, SEC_OID_PKCS12_KEY_BAG_ID,
+ "PKCS #12 Key Bag ID",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12CertAndCRLBagID, SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID,
+ "PKCS #12 Cert And CRL Bag ID",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12SecretBagID, SEC_OID_PKCS12_SECRET_BAG_ID,
+ "PKCS #12 Secret Bag ID",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12X509CertCRLBag, SEC_OID_PKCS12_X509_CERT_CRL_BAG,
+ "PKCS #12 X509 Cert CRL Bag",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12SDSICertBag, SEC_OID_PKCS12_SDSI_CERT_BAG,
+ "PKCS #12 SDSI Cert Bag",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12PBEWithSha1And128BitRC4,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4,
+ "PKCS #12 PBE With Sha1 and 128 Bit RC4",
+ CKM_NETSCAPE_PBE_SHA1_128_BIT_RC4, INVALID_CERT_EXTENSION ),
+ OD( pkcs12PBEWithSha1And40BitRC4,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4,
+ "PKCS #12 PBE With Sha1 and 40 Bit RC4",
+ CKM_NETSCAPE_PBE_SHA1_40_BIT_RC4, INVALID_CERT_EXTENSION ),
+ OD( pkcs12PBEWithSha1AndTripleDESCBC,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC,
+ "PKCS #12 PBE With Sha1 and Triple DES CBC",
+ CKM_NETSCAPE_PBE_SHA1_TRIPLE_DES_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs12PBEWithSha1And128BitRC2CBC,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC,
+ "PKCS #12 PBE With Sha1 and 128 Bit RC2 CBC",
+ CKM_NETSCAPE_PBE_SHA1_128_BIT_RC2_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs12PBEWithSha1And40BitRC2CBC,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC,
+ "PKCS #12 PBE With Sha1 and 40 Bit RC2 CBC",
+ CKM_NETSCAPE_PBE_SHA1_40_BIT_RC2_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs12RSAEncryptionWith128BitRC4,
+ SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_128_BIT_RC4,
+ "PKCS #12 RSA Encryption with 128 Bit RC4",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12RSAEncryptionWith40BitRC4,
+ SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_40_BIT_RC4,
+ "PKCS #12 RSA Encryption with 40 Bit RC4",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12RSAEncryptionWithTripleDES,
+ SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_TRIPLE_DES,
+ "PKCS #12 RSA Encryption with Triple DES",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12RSASignatureWithSHA1Digest,
+ SEC_OID_PKCS12_RSA_SIGNATURE_WITH_SHA1_DIGEST,
+ "PKCS #12 RSA Encryption with Triple DES",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* DSA signatures */
+ OD( ansix9DSASignature, SEC_OID_ANSIX9_DSA_SIGNATURE,
+ "ANSI X9.57 DSA Signature", CKM_DSA, INVALID_CERT_EXTENSION ),
+ OD( ansix9DSASignaturewithSHA1Digest,
+ SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST,
+ "ANSI X9.57 DSA Signature with SHA1 Digest",
+ CKM_DSA_SHA1, INVALID_CERT_EXTENSION ),
+ OD( bogusDSASignaturewithSHA1Digest,
+ SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST,
+ "FORTEZZA DSA Signature with SHA1 Digest",
+ CKM_DSA_SHA1, INVALID_CERT_EXTENSION ),
+
+ /* verisign oids */
+ OD( verisignUserNotices, SEC_OID_VERISIGN_USER_NOTICES,
+ "Verisign User Notices",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* pkix oids */
+ OD( pkixCPSPointerQualifier, SEC_OID_PKIX_CPS_POINTER_QUALIFIER,
+ "PKIX CPS Pointer Qualifier",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixUserNoticeQualifier, SEC_OID_PKIX_USER_NOTICE_QUALIFIER,
+ "PKIX User Notice Qualifier",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ OD( pkixOCSP, SEC_OID_PKIX_OCSP,
+ "PKIX Online Certificate Status Protocol",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixOCSPBasicResponse, SEC_OID_PKIX_OCSP_BASIC_RESPONSE,
+ "OCSP Basic Response", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixOCSPNonce, SEC_OID_PKIX_OCSP_NONCE,
+ "OCSP Nonce Extension", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixOCSPCRL, SEC_OID_PKIX_OCSP_CRL,
+ "OCSP CRL Reference Extension",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixOCSPResponse, SEC_OID_PKIX_OCSP_RESPONSE,
+ "OCSP Response Types Extension",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixOCSPNoCheck, SEC_OID_PKIX_OCSP_NO_CHECK,
+ "OCSP No Check Extension",
+ CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION ),
+ OD( pkixOCSPArchiveCutoff, SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF,
+ "OCSP Archive Cutoff Extension",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixOCSPServiceLocator, SEC_OID_PKIX_OCSP_SERVICE_LOCATOR,
+ "OCSP Service Locator Extension",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ OD( pkixRegCtrlRegToken, SEC_OID_PKIX_REGCTRL_REGTOKEN,
+ "PKIX CRMF Registration Control, Registration Token",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixRegCtrlAuthenticator, SEC_OID_PKIX_REGCTRL_AUTHENTICATOR,
+ "PKIX CRMF Registration Control, Registration Authenticator",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkixRegCtrlPKIPubInfo, SEC_OID_PKIX_REGCTRL_PKIPUBINFO,
+ "PKIX CRMF Registration Control, PKI Publication Info",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixRegCtrlPKIArchOptions,
+ SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS,
+ "PKIX CRMF Registration Control, PKI Archive Options",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixRegCtrlOldCertID, SEC_OID_PKIX_REGCTRL_OLD_CERT_ID,
+ "PKIX CRMF Registration Control, Old Certificate ID",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixRegCtrlProtEncKey, SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY,
+ "PKIX CRMF Registration Control, Protocol Encryption Key",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixRegInfoUTF8Pairs, SEC_OID_PKIX_REGINFO_UTF8_PAIRS,
+ "PKIX CRMF Registration Info, UTF8 Pairs",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixRegInfoCertReq, SEC_OID_PKIX_REGINFO_CERT_REQUEST,
+ "PKIX CRMF Registration Info, Certificate Request",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixExtendedKeyUsageServerAuth,
+ SEC_OID_EXT_KEY_USAGE_SERVER_AUTH,
+ "TLS Web Server Authentication Certificate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixExtendedKeyUsageClientAuth,
+ SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH,
+ "TLS Web Client Authentication Certificate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixExtendedKeyUsageCodeSign, SEC_OID_EXT_KEY_USAGE_CODE_SIGN,
+ "Code Signing Certificate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixExtendedKeyUsageEMailProtect,
+ SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT,
+ "E-Mail Protection Certificate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixExtendedKeyUsageTimeStamp,
+ SEC_OID_EXT_KEY_USAGE_TIME_STAMP,
+ "Time Stamping Certifcate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+ OD( pkixOCSPResponderExtendedKeyUsage, SEC_OID_OCSP_RESPONDER,
+ "OCSP Responder Certificate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION),
+
+ /* Netscape Algorithm OIDs */
+
+ OD( netscapeSMimeKEA, SEC_OID_NETSCAPE_SMIME_KEA,
+ "Netscape S/MIME KEA", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* Skipjack OID -- ### mwelch temporary */
+ OD( skipjackCBC, SEC_OID_FORTEZZA_SKIPJACK,
+ "Skipjack CBC64", CKM_SKIPJACK_CBC64, INVALID_CERT_EXTENSION ),
+
+ /* pkcs12 v2 oids */
+ OD( pkcs12V2PBEWithSha1And128BitRC4,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4,
+ "PKCS12 V2 PBE With SHA1 And 128 Bit RC4",
+ CKM_PBE_SHA1_RC4_128, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V2PBEWithSha1And40BitRC4,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4,
+ "PKCS12 V2 PBE With SHA1 And 40 Bit RC4",
+ CKM_PBE_SHA1_RC4_40, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V2PBEWithSha1And3KeyTripleDEScbc,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC,
+ "PKCS12 V2 PBE With SHA1 And 3KEY Triple DES-cbc",
+ CKM_PBE_SHA1_DES3_EDE_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V2PBEWithSha1And2KeyTripleDEScbc,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC,
+ "PKCS12 V2 PBE With SHA1 And 2KEY Triple DES-cbc",
+ CKM_PBE_SHA1_DES2_EDE_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V2PBEWithSha1And128BitRC2cbc,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC,
+ "PKCS12 V2 PBE With SHA1 And 128 Bit RC2 CBC",
+ CKM_PBE_SHA1_RC2_128_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V2PBEWithSha1And40BitRC2cbc,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC,
+ "PKCS12 V2 PBE With SHA1 And 40 Bit RC2 CBC",
+ CKM_PBE_SHA1_RC2_40_CBC, INVALID_CERT_EXTENSION ),
+ OD( pkcs12SafeContentsID, SEC_OID_PKCS12_SAFE_CONTENTS_ID,
+ "PKCS #12 Safe Contents ID",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12PKCS8ShroudedKeyBagID,
+ SEC_OID_PKCS12_PKCS8_SHROUDED_KEY_BAG_ID,
+ "PKCS #12 Safe Contents ID",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V1KeyBag, SEC_OID_PKCS12_V1_KEY_BAG_ID,
+ "PKCS #12 V1 Key Bag",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V1PKCS8ShroudedKeyBag,
+ SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID,
+ "PKCS #12 V1 PKCS8 Shrouded Key Bag",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V1CertBag, SEC_OID_PKCS12_V1_CERT_BAG_ID,
+ "PKCS #12 V1 Cert Bag",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V1CRLBag, SEC_OID_PKCS12_V1_CRL_BAG_ID,
+ "PKCS #12 V1 CRL Bag",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V1SecretBag, SEC_OID_PKCS12_V1_SECRET_BAG_ID,
+ "PKCS #12 V1 Secret Bag",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12V1SafeContentsBag, SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID,
+ "PKCS #12 V1 Safe Contents Bag",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ OD( pkcs9X509Certificate, SEC_OID_PKCS9_X509_CERT,
+ "PKCS #9 X509 Certificate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9SDSICertificate, SEC_OID_PKCS9_SDSI_CERT,
+ "PKCS #9 SDSI Certificate",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9X509CRL, SEC_OID_PKCS9_X509_CRL,
+ "PKCS #9 X509 CRL", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9FriendlyName, SEC_OID_PKCS9_FRIENDLY_NAME,
+ "PKCS #9 Friendly Name",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9LocalKeyID, SEC_OID_PKCS9_LOCAL_KEY_ID,
+ "PKCS #9 Local Key ID",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs12KeyUsageAttr, SEC_OID_BOGUS_KEY_USAGE,
+ "Bogus Key Usage", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( dhPublicKey, SEC_OID_X942_DIFFIE_HELMAN_KEY,
+ "Diffie-Helman Public Key", CKM_DH_PKCS_DERIVE,
+ INVALID_CERT_EXTENSION ),
+ OD( netscapeNickname, SEC_OID_NETSCAPE_NICKNAME,
+ "Netscape Nickname", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* Cert Server specific OIDs */
+ OD( netscapeRecoveryRequest, SEC_OID_NETSCAPE_RECOVERY_REQUEST,
+ "Recovery Request OID",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ OD( nsExtAIACertRenewal, SEC_OID_CERT_RENEWAL_LOCATOR,
+ "Certificate Renewal Locator OID", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+
+ OD( nsExtCertScopeOfUse, SEC_OID_NS_CERT_EXT_SCOPE_OF_USE,
+ "Certificate Scope-of-Use Extension", CKM_INVALID_MECHANISM,
+ SUPPORTED_CERT_EXTENSION ),
+
+ /* CMS stuff */
+ OD( cmsESDH, SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN,
+ "Ephemeral-Static Diffie-Hellman", CKM_INVALID_MECHANISM /* XXX */,
+ INVALID_CERT_EXTENSION ),
+ OD( cms3DESwrap, SEC_OID_CMS_3DES_KEY_WRAP,
+ "CMS 3DES Key Wrap", CKM_INVALID_MECHANISM /* XXX */,
+ INVALID_CERT_EXTENSION ),
+ OD( cmsRC2wrap, SEC_OID_CMS_RC2_KEY_WRAP,
+ "CMS RC2 Key Wrap", CKM_INVALID_MECHANISM /* XXX */,
+ INVALID_CERT_EXTENSION ),
+ OD( smimeEncryptionKeyPreference, SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE,
+ "S/MIME Encryption Key Preference",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* AES algorithm OIDs */
+ OD( aes128_ECB, SEC_OID_AES_128_ECB,
+ "AES-128-ECB", CKM_AES_ECB, INVALID_CERT_EXTENSION ),
+ OD( aes128_CBC, SEC_OID_AES_128_CBC,
+ "AES-128-CBC", CKM_AES_CBC, INVALID_CERT_EXTENSION ),
+ OD( aes192_ECB, SEC_OID_AES_192_ECB,
+ "AES-192-ECB", CKM_AES_ECB, INVALID_CERT_EXTENSION ),
+ OD( aes192_CBC, SEC_OID_AES_192_CBC,
+ "AES-192-CBC", CKM_AES_CBC, INVALID_CERT_EXTENSION ),
+ OD( aes256_ECB, SEC_OID_AES_256_ECB,
+ "AES-256-ECB", CKM_AES_ECB, INVALID_CERT_EXTENSION ),
+ OD( aes256_CBC, SEC_OID_AES_256_CBC,
+ "AES-256-CBC", CKM_AES_CBC, INVALID_CERT_EXTENSION ),
+
+ /* More bogus DSA OIDs */
+ OD( sdn702DSASignature, SEC_OID_SDN702_DSA_SIGNATURE,
+ "SDN.702 DSA Signature", CKM_DSA_SHA1, INVALID_CERT_EXTENSION ),
+
+ OD( ms_smimeEncryptionKeyPreference,
+ SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE,
+ "Microsoft S/MIME Encryption Key Preference",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ OD( sha256, SEC_OID_SHA256, "SHA-256", CKM_SHA256, INVALID_CERT_EXTENSION),
+ OD( sha384, SEC_OID_SHA384, "SHA-384", CKM_SHA384, INVALID_CERT_EXTENSION),
+ OD( sha512, SEC_OID_SHA512, "SHA-512", CKM_SHA512, INVALID_CERT_EXTENSION),
+
+ OD( pkcs1SHA256WithRSAEncryption, SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION,
+ "PKCS #1 SHA-256 With RSA Encryption", CKM_SHA256_RSA_PKCS,
+ INVALID_CERT_EXTENSION ),
+ OD( pkcs1SHA384WithRSAEncryption, SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION,
+ "PKCS #1 SHA-384 With RSA Encryption", CKM_SHA384_RSA_PKCS,
+ INVALID_CERT_EXTENSION ),
+ OD( pkcs1SHA512WithRSAEncryption, SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION,
+ "PKCS #1 SHA-512 With RSA Encryption", CKM_SHA512_RSA_PKCS,
+ INVALID_CERT_EXTENSION ),
+
+ OD( aes128_KEY_WRAP, SEC_OID_AES_128_KEY_WRAP,
+ "AES-128 Key Wrap", CKM_NETSCAPE_AES_KEY_WRAP, INVALID_CERT_EXTENSION),
+ OD( aes192_KEY_WRAP, SEC_OID_AES_192_KEY_WRAP,
+ "AES-192 Key Wrap", CKM_NETSCAPE_AES_KEY_WRAP, INVALID_CERT_EXTENSION),
+ OD( aes256_KEY_WRAP, SEC_OID_AES_256_KEY_WRAP,
+ "AES-256 Key Wrap", CKM_NETSCAPE_AES_KEY_WRAP, INVALID_CERT_EXTENSION),
+
+ /* Elliptic Curve Cryptography (ECC) OIDs */
+ OD( ansix962ECPublicKey, SEC_OID_ANSIX962_EC_PUBLIC_KEY,
+ "X9.62 elliptic curve public key", CKM_ECDH1_DERIVE,
+ INVALID_CERT_EXTENSION ),
+ OD( ansix962SignaturewithSHA1Digest,
+ SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE,
+ "X9.62 ECDSA signature with SHA1", CKM_ECDSA_SHA1,
+ INVALID_CERT_EXTENSION ),
+
+ /* Named curves */
+
+ /* ANSI X9.62 named elliptic curves (prime field) */
+ OD( ansiX962prime192v1, SEC_OID_ANSIX962_EC_PRIME192V1,
+ "ANSI X9.62 elliptic curve prime192v1 (aka secp192r1, NIST P-192)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime192v2, SEC_OID_ANSIX962_EC_PRIME192V2,
+ "ANSI X9.62 elliptic curve prime192v2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime192v3, SEC_OID_ANSIX962_EC_PRIME192V3,
+ "ANSI X9.62 elliptic curve prime192v3",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime239v1, SEC_OID_ANSIX962_EC_PRIME239V1,
+ "ANSI X9.62 elliptic curve prime239v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime239v2, SEC_OID_ANSIX962_EC_PRIME239V2,
+ "ANSI X9.62 elliptic curve prime239v2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime239v3, SEC_OID_ANSIX962_EC_PRIME239V3,
+ "ANSI X9.62 elliptic curve prime239v3",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962prime256v1, SEC_OID_ANSIX962_EC_PRIME256V1,
+ "ANSI X9.62 elliptic curve prime256v1 (aka secp256r1, NIST P-256)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+
+ /* SECG named elliptic curves (prime field) */
+ OD( secgECsecp112r1, SEC_OID_SECG_EC_SECP112R1,
+ "SECG elliptic curve secp112r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp112r2, SEC_OID_SECG_EC_SECP112R2,
+ "SECG elliptic curve secp112r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp128r1, SEC_OID_SECG_EC_SECP128R1,
+ "SECG elliptic curve secp128r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp128r2, SEC_OID_SECG_EC_SECP128R2,
+ "SECG elliptic curve secp128r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp160k1, SEC_OID_SECG_EC_SECP160K1,
+ "SECG elliptic curve secp160k1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp160r1, SEC_OID_SECG_EC_SECP160R1,
+ "SECG elliptic curve secp160r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp160r2, SEC_OID_SECG_EC_SECP160R2,
+ "SECG elliptic curve secp160r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp192k1, SEC_OID_SECG_EC_SECP192K1,
+ "SECG elliptic curve secp192k1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp224k1, SEC_OID_SECG_EC_SECP224K1,
+ "SECG elliptic curve secp224k1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp224r1, SEC_OID_SECG_EC_SECP224R1,
+ "SECG elliptic curve secp224r1 (aka NIST P-224)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp256k1, SEC_OID_SECG_EC_SECP256K1,
+ "SECG elliptic curve secp256k1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp384r1, SEC_OID_SECG_EC_SECP384R1,
+ "SECG elliptic curve secp384r1 (aka NIST P-384)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsecp521r1, SEC_OID_SECG_EC_SECP521R1,
+ "SECG elliptic curve secp521r1 (aka NIST P-521)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+
+ /* ANSI X9.62 named elliptic curves (characteristic two field) */
+ OD( ansiX962c2pnb163v1, SEC_OID_ANSIX962_EC_C2PNB163V1,
+ "ANSI X9.62 elliptic curve c2pnb163v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb163v2, SEC_OID_ANSIX962_EC_C2PNB163V2,
+ "ANSI X9.62 elliptic curve c2pnb163v2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb163v3, SEC_OID_ANSIX962_EC_C2PNB163V3,
+ "ANSI X9.62 elliptic curve c2pnb163v3",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb176v1, SEC_OID_ANSIX962_EC_C2PNB176V1,
+ "ANSI X9.62 elliptic curve c2pnb176v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb191v1, SEC_OID_ANSIX962_EC_C2TNB191V1,
+ "ANSI X9.62 elliptic curve c2tnb191v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb191v2, SEC_OID_ANSIX962_EC_C2TNB191V2,
+ "ANSI X9.62 elliptic curve c2tnb191v2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb191v3, SEC_OID_ANSIX962_EC_C2TNB191V3,
+ "ANSI X9.62 elliptic curve c2tnb191v3",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2onb191v4, SEC_OID_ANSIX962_EC_C2ONB191V4,
+ "ANSI X9.62 elliptic curve c2onb191v4",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2onb191v5, SEC_OID_ANSIX962_EC_C2ONB191V5,
+ "ANSI X9.62 elliptic curve c2onb191v5",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb208w1, SEC_OID_ANSIX962_EC_C2PNB208W1,
+ "ANSI X9.62 elliptic curve c2pnb208w1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb239v1, SEC_OID_ANSIX962_EC_C2TNB239V1,
+ "ANSI X9.62 elliptic curve c2tnb239v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb239v2, SEC_OID_ANSIX962_EC_C2TNB239V2,
+ "ANSI X9.62 elliptic curve c2tnb239v2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb239v3, SEC_OID_ANSIX962_EC_C2TNB239V3,
+ "ANSI X9.62 elliptic curve c2tnb239v3",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2onb239v4, SEC_OID_ANSIX962_EC_C2ONB239V4,
+ "ANSI X9.62 elliptic curve c2onb239v4",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2onb239v5, SEC_OID_ANSIX962_EC_C2ONB239V5,
+ "ANSI X9.62 elliptic curve c2onb239v5",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb272w1, SEC_OID_ANSIX962_EC_C2PNB272W1,
+ "ANSI X9.62 elliptic curve c2pnb272w1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb304w1, SEC_OID_ANSIX962_EC_C2PNB304W1,
+ "ANSI X9.62 elliptic curve c2pnb304w1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb359v1, SEC_OID_ANSIX962_EC_C2TNB359V1,
+ "ANSI X9.62 elliptic curve c2tnb359v1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2pnb368w1, SEC_OID_ANSIX962_EC_C2PNB368W1,
+ "ANSI X9.62 elliptic curve c2pnb368w1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansiX962c2tnb431r1, SEC_OID_ANSIX962_EC_C2TNB431R1,
+ "ANSI X9.62 elliptic curve c2tnb431r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+
+ /* SECG named elliptic curves (characterisitic two field) */
+ OD( secgECsect113r1, SEC_OID_SECG_EC_SECT113R1,
+ "SECG elliptic curve sect113r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect113r2, SEC_OID_SECG_EC_SECT113R2,
+ "SECG elliptic curve sect113r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect131r1, SEC_OID_SECG_EC_SECT131R1,
+ "SECG elliptic curve sect131r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect131r2, SEC_OID_SECG_EC_SECT131R2,
+ "SECG elliptic curve sect131r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect163k1, SEC_OID_SECG_EC_SECT163K1,
+ "SECG elliptic curve sect163k1 (aka NIST K-163)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect163r1, SEC_OID_SECG_EC_SECT163R1,
+ "SECG elliptic curve sect163r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect163r2, SEC_OID_SECG_EC_SECT163R2,
+ "SECG elliptic curve sect163r2 (aka NIST B-163)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect193r1, SEC_OID_SECG_EC_SECT193R1,
+ "SECG elliptic curve sect193r1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect193r2, SEC_OID_SECG_EC_SECT193R2,
+ "SECG elliptic curve sect193r2",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect233k1, SEC_OID_SECG_EC_SECT233K1,
+ "SECG elliptic curve sect233k1 (aka NIST K-233)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect233r1, SEC_OID_SECG_EC_SECT233R1,
+ "SECG elliptic curve sect233r1 (aka NIST B-233)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect239k1, SEC_OID_SECG_EC_SECT239K1,
+ "SECG elliptic curve sect239k1",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect283k1, SEC_OID_SECG_EC_SECT283K1,
+ "SECG elliptic curve sect283k1 (aka NIST K-283)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect283r1, SEC_OID_SECG_EC_SECT283R1,
+ "SECG elliptic curve sect283r1 (aka NIST B-283)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect409k1, SEC_OID_SECG_EC_SECT409K1,
+ "SECG elliptic curve sect409k1 (aka NIST K-409)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect409r1, SEC_OID_SECG_EC_SECT409R1,
+ "SECG elliptic curve sect409r1 (aka NIST B-409)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect571k1, SEC_OID_SECG_EC_SECT571K1,
+ "SECG elliptic curve sect571k1 (aka NIST K-571)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( secgECsect571r1, SEC_OID_SECG_EC_SECT571R1,
+ "SECG elliptic curve sect571r1 (aka NIST B-571)",
+ CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+
+ OD( netscapeAOLScreenname, SEC_OID_NETSCAPE_AOLSCREENNAME,
+ "AOL Screenname", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+
+ OD( x520SurName, SEC_OID_AVA_SURNAME,
+ "X520 Title", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520SerialNumber, SEC_OID_AVA_SERIAL_NUMBER,
+ "X520 Serial Number", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520StreetAddress, SEC_OID_AVA_STREET_ADDRESS,
+ "X520 Street Address", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520Title, SEC_OID_AVA_TITLE,
+ "X520 Title", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520PostalAddress, SEC_OID_AVA_POSTAL_ADDRESS,
+ "X520 Postal Address", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520PostalCode, SEC_OID_AVA_POSTAL_CODE,
+ "X520 Postal Code", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520PostOfficeBox, SEC_OID_AVA_POST_OFFICE_BOX,
+ "X520 Post Office Box", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520GivenName, SEC_OID_AVA_GIVEN_NAME,
+ "X520 Given Name", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520Initials, SEC_OID_AVA_INITIALS,
+ "X520 Initials", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520GenerationQualifier, SEC_OID_AVA_GENERATION_QUALIFIER,
+ "X520 Generation Qualifier",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520HouseIdentifier, SEC_OID_AVA_HOUSE_IDENTIFIER,
+ "X520 House Identifier",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( x520Pseudonym, SEC_OID_AVA_PSEUDONYM,
+ "X520 Pseudonym", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* More OIDs */
+ OD( pkixCAIssuers, SEC_OID_PKIX_CA_ISSUERS,
+ "PKIX CA issuers access method",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs9ExtensionRequest, SEC_OID_PKCS9_EXTENSION_REQUEST,
+ "PKCS #9 Extension Request",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+ /* more ECC Signature Oids */
+ OD( ansix962SignatureRecommended,
+ SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST,
+ "X9.62 ECDSA signature with recommended digest", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansix962SignatureSpecified,
+ SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST,
+ "X9.62 ECDSA signature with specified digest", CKM_ECDSA,
+ INVALID_CERT_EXTENSION ),
+ OD( ansix962SignaturewithSHA224Digest,
+ SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE,
+ "X9.62 ECDSA signature with SHA224", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansix962SignaturewithSHA256Digest,
+ SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE,
+ "X9.62 ECDSA signature with SHA256", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansix962SignaturewithSHA384Digest,
+ SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE,
+ "X9.62 ECDSA signature with SHA384", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( ansix962SignaturewithSHA512Digest,
+ SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE,
+ "X9.62 ECDSA signature with SHA512", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+
+ /* More id-ce and id-pe OIDs from RFC 3280 */
+ OD( x509HoldInstructionCode, SEC_OID_X509_HOLD_INSTRUCTION_CODE,
+ "CRL Hold Instruction Code", CKM_INVALID_MECHANISM,
+ UNSUPPORTED_CERT_EXTENSION ),
+ OD( x509DeltaCRLIndicator, SEC_OID_X509_DELTA_CRL_INDICATOR,
+ "Delta CRL Indicator", CKM_INVALID_MECHANISM,
+ FAKE_SUPPORTED_CERT_EXTENSION ),
+ OD( x509IssuingDistributionPoint, SEC_OID_X509_ISSUING_DISTRIBUTION_POINT,
+ "Issuing Distribution Point", CKM_INVALID_MECHANISM,
+ FAKE_SUPPORTED_CERT_EXTENSION ),
+ OD( x509CertIssuer, SEC_OID_X509_CERT_ISSUER,
+ "Certificate Issuer Extension",CKM_INVALID_MECHANISM,
+ FAKE_SUPPORTED_CERT_EXTENSION ),
+ OD( x509FreshestCRL, SEC_OID_X509_FRESHEST_CRL,
+ "Freshest CRL", CKM_INVALID_MECHANISM,
+ UNSUPPORTED_CERT_EXTENSION ),
+ OD( x509InhibitAnyPolicy, SEC_OID_X509_INHIBIT_ANY_POLICY,
+ "Inhibit Any Policy", CKM_INVALID_MECHANISM,
+ FAKE_SUPPORTED_CERT_EXTENSION ),
+ OD( x509SubjectInfoAccess, SEC_OID_X509_SUBJECT_INFO_ACCESS,
+ "Subject Info Access", CKM_INVALID_MECHANISM,
+ UNSUPPORTED_CERT_EXTENSION ),
+
+ /* Camellia algorithm OIDs */
+ OD( camellia128_CBC, SEC_OID_CAMELLIA_128_CBC,
+ "CAMELLIA-128-CBC", CKM_CAMELLIA_CBC, INVALID_CERT_EXTENSION ),
+ OD( camellia192_CBC, SEC_OID_CAMELLIA_192_CBC,
+ "CAMELLIA-192-CBC", CKM_CAMELLIA_CBC, INVALID_CERT_EXTENSION ),
+ OD( camellia256_CBC, SEC_OID_CAMELLIA_256_CBC,
+ "CAMELLIA-256-CBC", CKM_CAMELLIA_CBC, INVALID_CERT_EXTENSION ),
+
+ /* PKCS 5 v2 OIDS */
+ OD( pkcs5Pbkdf2, SEC_OID_PKCS5_PBKDF2,
+ "PKCS #5 Password Based Key Dervive Function v2 ",
+ CKM_PKCS5_PBKD2, INVALID_CERT_EXTENSION ),
+ OD( pkcs5Pbes2, SEC_OID_PKCS5_PBES2,
+ "PKCS #5 Password Based Encryption v2 ",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( pkcs5Pbmac1, SEC_OID_PKCS5_PBMAC1,
+ "PKCS #5 Password Based Authentication v1 ",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+ OD( hmac_sha1, SEC_OID_HMAC_SHA1, "HMAC SHA-1",
+ CKM_SHA_1_HMAC, INVALID_CERT_EXTENSION ),
+ OD( hmac_sha224, SEC_OID_HMAC_SHA224, "HMAC SHA-224",
+ CKM_SHA224_HMAC, INVALID_CERT_EXTENSION ),
+ OD( hmac_sha256, SEC_OID_HMAC_SHA256, "HMAC SHA-256",
+ CKM_SHA256_HMAC, INVALID_CERT_EXTENSION ),
+ OD( hmac_sha384, SEC_OID_HMAC_SHA384, "HMAC SHA-384",
+ CKM_SHA384_HMAC, INVALID_CERT_EXTENSION ),
+ OD( hmac_sha512, SEC_OID_HMAC_SHA512, "HMAC SHA-512",
+ CKM_SHA512_HMAC, INVALID_CERT_EXTENSION ),
+
+ /* SIA extension OIDs */
+ OD( x509SIATimeStamping, SEC_OID_PKIX_TIMESTAMPING,
+ "SIA Time Stamping", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+ OD( x509SIACaRepository, SEC_OID_PKIX_CA_REPOSITORY,
+ "SIA CA Repository", CKM_INVALID_MECHANISM,
+ INVALID_CERT_EXTENSION ),
+
+ OD( isoSHA1WithRSASignature, SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE,
+ "ISO SHA1 with RSA Signature",
+ CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ),
+
+};
+
+/*
+ * now the dynamic table. The dynamic table gets build at init time.
+ * and conceivably gets modified if the user loads new crypto modules.
+ * All this static data, and the allocated data to which it points,
+ * is protected by a global reader/writer lock.
+ * The c language guarantees that global and static data that is not
+ * explicitly initialized will be initialized with zeros. If we
+ * initialize it with zeros, the data goes into the initialized data
+ * secment, and increases the size of the library. By leaving it
+ * uninitialized, it is allocated in BSS, and does NOT increase the
+ * library size.
+ */
+static NSSRWLock * dynOidLock;
+static PLArenaPool * dynOidPool;
+static PLHashTable * dynOidHash;
+static SECOidData ** dynOidTable; /* not in the pool */
+static int dynOidEntriesAllocated;
+static int dynOidEntriesUsed;
+
+/* Creates NSSRWLock and dynOidPool at initialization time.
+*/
+static SECStatus
+secoid_InitDynOidData(void)
+{
+ SECStatus rv = SECSuccess;
+
+ dynOidLock = NSSRWLock_New(1, "dynamic OID data");
+ if (!dynOidLock) {
+ return SECFailure; /* Error code should already be set. */
+ }
+ dynOidPool = PORT_NewArena(2048);
+ if (!dynOidPool) {
+ rv = SECFailure /* Error code should already be set. */;
+ }
+ return rv;
+}
+
+/* Add oidData to hash table. Caller holds write lock dynOidLock. */
+static SECStatus
+secoid_HashDynamicOiddata(const SECOidData * oid)
+{
+ PLHashEntry *entry;
+
+ if (!dynOidHash) {
+ dynOidHash = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
+ PL_CompareValues, NULL, NULL);
+ if ( !dynOidHash ) {
+ return SECFailure;
+ }
+ }
+
+ entry = PL_HashTableAdd( dynOidHash, &oid->oid, (void *)oid );
+ return entry ? SECSuccess : SECFailure;
+}
+
+
+/*
+ * Lookup a Dynamic OID. Dynamic OID's still change slowly, so it's
+ * cheaper to rehash the table when it changes than it is to do the loop
+ * each time.
+ */
+static SECOidData *
+secoid_FindDynamic(const SECItem *key)
+{
+ SECOidData *ret = NULL;
+
+ if (dynOidHash) {
+ NSSRWLock_LockRead(dynOidLock);
+ if (dynOidHash) { /* must check it again with lock held. */
+ ret = (SECOidData *)PL_HashTableLookup(dynOidHash, key);
+ }
+ NSSRWLock_UnlockRead(dynOidLock);
+ }
+ if (ret == NULL) {
+ PORT_SetError(SEC_ERROR_UNRECOGNIZED_OID);
+ }
+ return ret;
+}
+
+static SECOidData *
+secoid_FindDynamicByTag(SECOidTag tagnum)
+{
+ SECOidData *data = NULL;
+ int tagNumDiff;
+
+ if (tagnum < SEC_OID_TOTAL) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ return NULL;
+ }
+ tagNumDiff = tagnum - SEC_OID_TOTAL;
+
+ if (dynOidTable) {
+ NSSRWLock_LockRead(dynOidLock);
+ if (dynOidTable != NULL && /* must check it again with lock held. */
+ tagNumDiff < dynOidEntriesUsed) {
+ data = dynOidTable[tagNumDiff];
+ }
+ NSSRWLock_UnlockRead(dynOidLock);
+ }
+ if (data == NULL) {
+ PORT_SetError(SEC_ERROR_UNRECOGNIZED_OID);
+ }
+ return data;
+}
+
+/*
+ * This routine is thread safe now.
+ */
+SECOidTag
+SECOID_AddEntry(const SECOidData * src)
+{
+ SECOidData * dst;
+ SECOidData **table;
+ SECOidTag ret = SEC_OID_UNKNOWN;
+ SECStatus rv;
+ int tableEntries;
+ int used;
+
+ if (!src || !src->oid.data || !src->oid.len || \
+ !src->desc || !strlen(src->desc)) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return ret;
+ }
+ if (src->supportedExtension != INVALID_CERT_EXTENSION &&
+ src->supportedExtension != UNSUPPORTED_CERT_EXTENSION &&
+ src->supportedExtension != SUPPORTED_CERT_EXTENSION ) {
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return ret;
+ }
+
+ if (!dynOidPool || !dynOidLock) {
+ PORT_SetError(SEC_ERROR_NOT_INITIALIZED);
+ return ret;
+ }
+
+ NSSRWLock_LockWrite(dynOidLock);
+
+ /* We've just acquired the write lock, and now we call FindOIDTag
+ ** which will acquire and release the read lock. NSSRWLock has been
+ ** designed to allow this very case without deadlock. This approach
+ ** makes the test for the presence of the OID, and the subsequent
+ ** addition of the OID to the table a single atomic write operation.
+ */
+ ret = SECOID_FindOIDTag(&src->oid);
+ if (ret != SEC_OID_UNKNOWN) {
+ /* we could return an error here, but I chose not to do that.
+ ** This way, if we add an OID to the shared library's built in
+ ** list of OIDs in some future release, and that OID is the same
+ ** as some OID that a program has been adding, the program will
+ ** not suddenly stop working.
+ */
+ goto done;
+ }
+
+ table = dynOidTable;
+ tableEntries = dynOidEntriesAllocated;
+ used = dynOidEntriesUsed;
+
+ if (used + 1 > tableEntries) {
+ SECOidData **newTable;
+ int newTableEntries = tableEntries + 16;
+
+ newTable = (SECOidData **)PORT_Realloc(table,
+ newTableEntries * sizeof(SECOidData *));
+ if (newTable == NULL) {
+ goto done;
+ }
+ dynOidTable = table = newTable;
+ dynOidEntriesAllocated = tableEntries = newTableEntries;
+ }
+
+ /* copy oid structure */
+ dst = PORT_ArenaNew(dynOidPool, SECOidData);
+ if (!dst) {
+ goto done;
+ }
+ rv = SECITEM_CopyItem(dynOidPool, &dst->oid, &src->oid);
+ if (rv != SECSuccess) {
+ goto done;
+ }
+ dst->desc = PORT_ArenaStrdup(dynOidPool, src->desc);
+ if (!dst->desc) {
+ goto done;
+ }
+ dst->offset = (SECOidTag)(used + SEC_OID_TOTAL);
+ dst->mechanism = src->mechanism;
+ dst->supportedExtension = src->supportedExtension;
+
+ rv = secoid_HashDynamicOiddata(dst);
+ if ( rv == SECSuccess ) {
+ table[used++] = dst;
+ dynOidEntriesUsed = used;
+ ret = dst->offset;
+ }
+done:
+ NSSRWLock_UnlockWrite(dynOidLock);
+ return ret;
+}
+
+
+/* normal static table processing */
+static PLHashTable *oidhash = NULL;
+static PLHashTable *oidmechhash = NULL;
+
+static PLHashNumber
+secoid_HashNumber(const void *key)
+{
+ return (PLHashNumber) key;
+}
+
+
+SECStatus
+SECOID_Init(void)
+{
+ PLHashEntry *entry;
+ const SECOidData *oid;
+ int i;
+
+ if (oidhash) {
+ return SECSuccess; /* already initialized */
+ }
+
+ if (secoid_InitDynOidData() != SECSuccess) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ PORT_Assert(0); /* this function should never fail */
+ return SECFailure;
+ }
+
+ oidhash = PL_NewHashTable(0, SECITEM_Hash, SECITEM_HashCompare,
+ PL_CompareValues, NULL, NULL);
+ oidmechhash = PL_NewHashTable(0, secoid_HashNumber, PL_CompareValues,
+ PL_CompareValues, NULL, NULL);
+
+ if ( !oidhash || !oidmechhash) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ PORT_Assert(0); /*This function should never fail. */
+ return(SECFailure);
+ }
+
+ for ( i = 0; i < ( sizeof(oids) / sizeof(SECOidData) ); i++ ) {
+ oid = &oids[i];
+
+ PORT_Assert ( oid->offset == i );
+
+ entry = PL_HashTableAdd( oidhash, &oid->oid, (void *)oid );
+ if ( entry == NULL ) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ PORT_Assert(0); /*This function should never fail. */
+ return(SECFailure);
+ }
+
+ if ( oid->mechanism != CKM_INVALID_MECHANISM ) {
+ entry = PL_HashTableAdd( oidmechhash,
+ (void *)oid->mechanism, (void *)oid );
+ if ( entry == NULL ) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ PORT_Assert(0); /* This function should never fail. */
+ return(SECFailure);
+ }
+ }
+ }
+
+ PORT_Assert (i == SEC_OID_TOTAL);
+
+ return(SECSuccess);
+}
+
+SECOidData *
+SECOID_FindOIDByMechanism(unsigned long mechanism)
+{
+ SECOidData *ret;
+
+ PR_ASSERT(oidhash != NULL);
+
+ ret = PL_HashTableLookupConst ( oidmechhash, (void *)mechanism);
+ if ( ret == NULL ) {
+ PORT_SetError(SEC_ERROR_LIBRARY_FAILURE);
+ }
+
+ return (ret);
+}
+
+SECOidData *
+SECOID_FindOID(const SECItem *oid)
+{
+ SECOidData *ret;
+
+ PR_ASSERT(oidhash != NULL);
+
+ ret = PL_HashTableLookupConst ( oidhash, oid );
+ if ( ret == NULL ) {
+ ret = secoid_FindDynamic(oid);
+ if (ret == NULL) {
+ PORT_SetError(SEC_ERROR_UNRECOGNIZED_OID);
+ }
+ }
+
+ return(ret);
+}
+
+SECOidTag
+SECOID_FindOIDTag(const SECItem *oid)
+{
+ SECOidData *oiddata;
+
+ oiddata = SECOID_FindOID (oid);
+ if (oiddata == NULL)
+ return SEC_OID_UNKNOWN;
+
+ return oiddata->offset;
+}
+
+/* This really should return const. */
+SECOidData *
+SECOID_FindOIDByTag(SECOidTag tagnum)
+{
+
+ if (tagnum >= SEC_OID_TOTAL) {
+ return secoid_FindDynamicByTag(tagnum);
+ }
+
+ PORT_Assert((unsigned int)tagnum < (sizeof(oids) / sizeof(SECOidData)));
+ return (SECOidData *)(&oids[tagnum]);
+}
+
+PRBool SECOID_KnownCertExtenOID (SECItem *extenOid)
+{
+ SECOidData * oidData;
+
+ oidData = SECOID_FindOID (extenOid);
+ if (oidData == (SECOidData *)NULL)
+ return (PR_FALSE);
+ return ((oidData->supportedExtension == SUPPORTED_CERT_EXTENSION) ?
+ PR_TRUE : PR_FALSE);
+}
+
+
+const char *
+SECOID_FindOIDTagDescription(SECOidTag tagnum)
+{
+ const SECOidData *oidData = SECOID_FindOIDByTag(tagnum);
+ return oidData ? oidData->desc : 0;
+}
+
+/*
+ * free up the oid tables.
+ */
+SECStatus
+SECOID_Shutdown(void)
+{
+ if (oidhash) {
+ PL_HashTableDestroy(oidhash);
+ oidhash = NULL;
+ }
+ if (oidmechhash) {
+ PL_HashTableDestroy(oidmechhash);
+ oidmechhash = NULL;
+ }
+ /* Have to handle the case where the lock was created, but
+ ** the pool wasn't.
+ ** I'm not going to attempt to create the lock, just to protect
+ ** the destruction of data that probably isn't initialized anyway.
+ */
+ if (dynOidLock) {
+ NSSRWLock_LockWrite(dynOidLock);
+ if (dynOidHash) {
+ PL_HashTableDestroy(dynOidHash);
+ dynOidHash = NULL;
+ }
+ if (dynOidPool) {
+ PORT_FreeArena(dynOidPool, PR_FALSE);
+ dynOidPool = NULL;
+ }
+ if (dynOidTable) {
+ PORT_Free(dynOidTable);
+ dynOidTable = NULL;
+ }
+ dynOidEntriesAllocated = 0;
+ dynOidEntriesUsed = 0;
+
+ NSSRWLock_UnlockWrite(dynOidLock);
+ NSSRWLock_Destroy(dynOidLock);
+ dynOidLock = NULL;
+ } else {
+ /* Since dynOidLock doesn't exist, then all the data it protects
+ ** should be uninitialized. We'll check that (in DEBUG builds),
+ ** and then make sure it is so, in case NSS is reinitialized.
+ */
+ PORT_Assert(!dynOidHash && !dynOidPool && !dynOidTable && \
+ !dynOidEntriesAllocated && !dynOidEntriesUsed);
+ dynOidHash = NULL;
+ dynOidPool = NULL;
+ dynOidTable = NULL;
+ dynOidEntriesAllocated = 0;
+ dynOidEntriesUsed = 0;
+ }
+ return SECSuccess;
+}
diff --git a/security/nss/lib/util/secoid.h b/security/nss/lib/util/secoid.h
new file mode 100644
index 000000000..7f37e737c
--- /dev/null
+++ b/security/nss/lib/util/secoid.h
@@ -0,0 +1,152 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _SECOID_H_
+#define _SECOID_H_
+
+#include "utilrename.h"
+
+/*
+ * secoid.h - public data structures and prototypes for ASN.1 OID functions
+ *
+ * $Id$
+ */
+
+#include "plarena.h"
+
+#include "seccomon.h"
+#include "secoidt.h"
+#include "secasn1t.h"
+
+SEC_BEGIN_PROTOS
+
+extern const SEC_ASN1Template SECOID_AlgorithmIDTemplate[];
+
+/* This functions simply returns the address of the above-declared template. */
+SEC_ASN1_CHOOSER_DECLARE(SECOID_AlgorithmIDTemplate)
+
+/*
+ * OID handling routines
+ */
+extern SECOidData *SECOID_FindOID( const SECItem *oid);
+extern SECOidTag SECOID_FindOIDTag(const SECItem *oid);
+extern SECOidData *SECOID_FindOIDByTag(SECOidTag tagnum);
+extern SECOidData *SECOID_FindOIDByMechanism(unsigned long mechanism);
+
+/****************************************/
+/*
+** Algorithm id handling operations
+*/
+
+/*
+** Fill in an algorithm-ID object given a tag and some parameters.
+** "aid" where the DER encoded algorithm info is stored (memory
+** is allocated)
+** "tag" the tag number defining the algorithm
+** "params" if not NULL, the parameters to go with the algorithm
+*/
+extern SECStatus SECOID_SetAlgorithmID(PLArenaPool *arena, SECAlgorithmID *aid,
+ SECOidTag tag, SECItem *params);
+
+/*
+** Copy the "src" object to "dest". Memory is allocated in "dest" for
+** each of the appropriate sub-objects. Memory in "dest" is not freed
+** before memory is allocated (use SECOID_DestroyAlgorithmID(dest, PR_FALSE)
+** to do that).
+*/
+extern SECStatus SECOID_CopyAlgorithmID(PLArenaPool *arena, SECAlgorithmID *dest,
+ SECAlgorithmID *src);
+
+/*
+** Get the tag number for the given algorithm-id object.
+*/
+extern SECOidTag SECOID_GetAlgorithmTag(SECAlgorithmID *aid);
+
+/*
+** Destroy an algorithm-id object.
+** "aid" the certificate-request to destroy
+** "freeit" if PR_TRUE then free the object as well as its sub-objects
+*/
+extern void SECOID_DestroyAlgorithmID(SECAlgorithmID *aid, PRBool freeit);
+
+/*
+** Compare two algorithm-id objects, returning the difference between
+** them.
+*/
+extern SECComparison SECOID_CompareAlgorithmID(SECAlgorithmID *a,
+ SECAlgorithmID *b);
+
+extern PRBool SECOID_KnownCertExtenOID (SECItem *extenOid);
+
+/* Given a tag number, return a string describing it.
+ */
+extern const char *SECOID_FindOIDTagDescription(SECOidTag tagnum);
+
+/* Add a dynamic SECOidData to the dynamic OID table.
+** Routine copies the src entry, and returns the new SECOidTag.
+** Returns SEC_OID_INVALID if failed to add for some reason.
+*/
+extern SECOidTag SECOID_AddEntry(const SECOidData * src);
+
+/*
+ * initialize the oid data structures.
+ */
+extern SECStatus SECOID_Init(void);
+
+/*
+ * free up the oid data structures.
+ */
+extern SECStatus SECOID_Shutdown(void);
+
+/* if to->data is not NULL, and to->len is large enough to hold the result,
+ * then the resultant OID will be copyed into to->data, and to->len will be
+ * changed to show the actual OID length.
+ * Otherwise, memory for the OID will be allocated (from the caller's
+ * PLArenaPool, if pool is non-NULL) and to->data will receive the address
+ * of the allocated data, and to->len will receive the OID length.
+ * The original value of to->data is not freed when a new buffer is allocated.
+ *
+ * The input string may begin with "OID." and this still be ignored.
+ * The length of the input string is given in len. If len == 0, then
+ * len will be computed as strlen(from), meaning it must be NUL terminated.
+ * It is an error if from == NULL, or if *from == '\0'.
+ */
+extern SECStatus SEC_StringToOID(PLArenaPool *pool, SECItem *to,
+ const char *from, PRUint32 len);
+
+SEC_END_PROTOS
+
+#endif /* _SECOID_H_ */
diff --git a/security/nss/lib/util/secoidt.h b/security/nss/lib/util/secoidt.h
new file mode 100644
index 000000000..9591a9e5c
--- /dev/null
+++ b/security/nss/lib/util/secoidt.h
@@ -0,0 +1,476 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _SECOIDT_H_
+#define _SECOIDT_H_
+
+#include "utilrename.h"
+
+/*
+ * secoidt.h - public data structures for ASN.1 OID functions
+ *
+ * $Id$
+ */
+
+#include "secitem.h"
+
+typedef struct SECOidDataStr SECOidData;
+typedef struct SECAlgorithmIDStr SECAlgorithmID;
+
+/*
+** An X.500 algorithm identifier
+*/
+struct SECAlgorithmIDStr {
+ SECItem algorithm;
+ SECItem parameters;
+};
+
+/*
+ * Misc object IDs - these numbers are for convenient handling.
+ * They are mapped into real object IDs
+ *
+ * NOTE: the order of these entries must mach the array "oids" of SECOidData
+ * in util/secoid.c.
+ */
+typedef enum {
+ SEC_OID_UNKNOWN = 0,
+ SEC_OID_MD2 = 1,
+ SEC_OID_MD4 = 2,
+ SEC_OID_MD5 = 3,
+ SEC_OID_SHA1 = 4,
+ SEC_OID_RC2_CBC = 5,
+ SEC_OID_RC4 = 6,
+ SEC_OID_DES_EDE3_CBC = 7,
+ SEC_OID_RC5_CBC_PAD = 8,
+ SEC_OID_DES_ECB = 9,
+ SEC_OID_DES_CBC = 10,
+ SEC_OID_DES_OFB = 11,
+ SEC_OID_DES_CFB = 12,
+ SEC_OID_DES_MAC = 13,
+ SEC_OID_DES_EDE = 14,
+ SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE = 15,
+ SEC_OID_PKCS1_RSA_ENCRYPTION = 16,
+ SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION = 17,
+ SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION = 18,
+ SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION = 19,
+ SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION = 20,
+ SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC = 21,
+ SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC = 22,
+ SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC = 23,
+ SEC_OID_PKCS7 = 24,
+ SEC_OID_PKCS7_DATA = 25,
+ SEC_OID_PKCS7_SIGNED_DATA = 26,
+ SEC_OID_PKCS7_ENVELOPED_DATA = 27,
+ SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA = 28,
+ SEC_OID_PKCS7_DIGESTED_DATA = 29,
+ SEC_OID_PKCS7_ENCRYPTED_DATA = 30,
+ SEC_OID_PKCS9_EMAIL_ADDRESS = 31,
+ SEC_OID_PKCS9_UNSTRUCTURED_NAME = 32,
+ SEC_OID_PKCS9_CONTENT_TYPE = 33,
+ SEC_OID_PKCS9_MESSAGE_DIGEST = 34,
+ SEC_OID_PKCS9_SIGNING_TIME = 35,
+ SEC_OID_PKCS9_COUNTER_SIGNATURE = 36,
+ SEC_OID_PKCS9_CHALLENGE_PASSWORD = 37,
+ SEC_OID_PKCS9_UNSTRUCTURED_ADDRESS = 38,
+ SEC_OID_PKCS9_EXTENDED_CERTIFICATE_ATTRIBUTES = 39,
+ SEC_OID_PKCS9_SMIME_CAPABILITIES = 40,
+ SEC_OID_AVA_COMMON_NAME = 41,
+ SEC_OID_AVA_COUNTRY_NAME = 42,
+ SEC_OID_AVA_LOCALITY = 43,
+ SEC_OID_AVA_STATE_OR_PROVINCE = 44,
+ SEC_OID_AVA_ORGANIZATION_NAME = 45,
+ SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME = 46,
+ SEC_OID_AVA_DN_QUALIFIER = 47,
+ SEC_OID_AVA_DC = 48,
+
+ SEC_OID_NS_TYPE_GIF = 49,
+ SEC_OID_NS_TYPE_JPEG = 50,
+ SEC_OID_NS_TYPE_URL = 51,
+ SEC_OID_NS_TYPE_HTML = 52,
+ SEC_OID_NS_TYPE_CERT_SEQUENCE = 53,
+ SEC_OID_MISSI_KEA_DSS_OLD = 54,
+ SEC_OID_MISSI_DSS_OLD = 55,
+ SEC_OID_MISSI_KEA_DSS = 56,
+ SEC_OID_MISSI_DSS = 57,
+ SEC_OID_MISSI_KEA = 58,
+ SEC_OID_MISSI_ALT_KEA = 59,
+
+ /* Netscape private certificate extensions */
+ SEC_OID_NS_CERT_EXT_NETSCAPE_OK = 60,
+ SEC_OID_NS_CERT_EXT_ISSUER_LOGO = 61,
+ SEC_OID_NS_CERT_EXT_SUBJECT_LOGO = 62,
+ SEC_OID_NS_CERT_EXT_CERT_TYPE = 63,
+ SEC_OID_NS_CERT_EXT_BASE_URL = 64,
+ SEC_OID_NS_CERT_EXT_REVOCATION_URL = 65,
+ SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL = 66,
+ SEC_OID_NS_CERT_EXT_CA_CRL_URL = 67,
+ SEC_OID_NS_CERT_EXT_CA_CERT_URL = 68,
+ SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL = 69,
+ SEC_OID_NS_CERT_EXT_CA_POLICY_URL = 70,
+ SEC_OID_NS_CERT_EXT_HOMEPAGE_URL = 71,
+ SEC_OID_NS_CERT_EXT_ENTITY_LOGO = 72,
+ SEC_OID_NS_CERT_EXT_USER_PICTURE = 73,
+ SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME = 74,
+ SEC_OID_NS_CERT_EXT_COMMENT = 75,
+ SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL = 76,
+ SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME = 77,
+ SEC_OID_NS_KEY_USAGE_GOVT_APPROVED = 78,
+
+ /* x.509 v3 Extensions */
+ SEC_OID_X509_SUBJECT_DIRECTORY_ATTR = 79,
+ SEC_OID_X509_SUBJECT_KEY_ID = 80,
+ SEC_OID_X509_KEY_USAGE = 81,
+ SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD = 82,
+ SEC_OID_X509_SUBJECT_ALT_NAME = 83,
+ SEC_OID_X509_ISSUER_ALT_NAME = 84,
+ SEC_OID_X509_BASIC_CONSTRAINTS = 85,
+ SEC_OID_X509_NAME_CONSTRAINTS = 86,
+ SEC_OID_X509_CRL_DIST_POINTS = 87,
+ SEC_OID_X509_CERTIFICATE_POLICIES = 88,
+ SEC_OID_X509_POLICY_MAPPINGS = 89,
+ SEC_OID_X509_POLICY_CONSTRAINTS = 90,
+ SEC_OID_X509_AUTH_KEY_ID = 91,
+ SEC_OID_X509_EXT_KEY_USAGE = 92,
+ SEC_OID_X509_AUTH_INFO_ACCESS = 93,
+
+ SEC_OID_X509_CRL_NUMBER = 94,
+ SEC_OID_X509_REASON_CODE = 95,
+ SEC_OID_X509_INVALID_DATE = 96,
+ /* End of x.509 v3 Extensions */
+
+ SEC_OID_X500_RSA_ENCRYPTION = 97,
+
+ /* alg 1485 additions */
+ SEC_OID_RFC1274_UID = 98,
+ SEC_OID_RFC1274_MAIL = 99,
+
+ /* PKCS 12 additions */
+ SEC_OID_PKCS12 = 100,
+ SEC_OID_PKCS12_MODE_IDS = 101,
+ SEC_OID_PKCS12_ESPVK_IDS = 102,
+ SEC_OID_PKCS12_BAG_IDS = 103,
+ SEC_OID_PKCS12_CERT_BAG_IDS = 104,
+ SEC_OID_PKCS12_OIDS = 105,
+ SEC_OID_PKCS12_PBE_IDS = 106,
+ SEC_OID_PKCS12_SIGNATURE_IDS = 107,
+ SEC_OID_PKCS12_ENVELOPING_IDS = 108,
+ /* SEC_OID_PKCS12_OFFLINE_TRANSPORT_MODE,
+ SEC_OID_PKCS12_ONLINE_TRANSPORT_MODE, */
+ SEC_OID_PKCS12_PKCS8_KEY_SHROUDING = 109,
+ SEC_OID_PKCS12_KEY_BAG_ID = 110,
+ SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID = 111,
+ SEC_OID_PKCS12_SECRET_BAG_ID = 112,
+ SEC_OID_PKCS12_X509_CERT_CRL_BAG = 113,
+ SEC_OID_PKCS12_SDSI_CERT_BAG = 114,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4 = 115,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4 = 116,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC = 117,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC = 118,
+ SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC = 119,
+ SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_128_BIT_RC4 = 120,
+ SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_40_BIT_RC4 = 121,
+ SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_TRIPLE_DES = 122,
+ SEC_OID_PKCS12_RSA_SIGNATURE_WITH_SHA1_DIGEST = 123,
+ /* end of PKCS 12 additions */
+
+ /* DSA signatures */
+ SEC_OID_ANSIX9_DSA_SIGNATURE = 124,
+ SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST = 125,
+ SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST = 126,
+
+ /* Verisign OIDs */
+ SEC_OID_VERISIGN_USER_NOTICES = 127,
+
+ /* PKIX OIDs */
+ SEC_OID_PKIX_CPS_POINTER_QUALIFIER = 128,
+ SEC_OID_PKIX_USER_NOTICE_QUALIFIER = 129,
+ SEC_OID_PKIX_OCSP = 130,
+ SEC_OID_PKIX_OCSP_BASIC_RESPONSE = 131,
+ SEC_OID_PKIX_OCSP_NONCE = 132,
+ SEC_OID_PKIX_OCSP_CRL = 133,
+ SEC_OID_PKIX_OCSP_RESPONSE = 134,
+ SEC_OID_PKIX_OCSP_NO_CHECK = 135,
+ SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF = 136,
+ SEC_OID_PKIX_OCSP_SERVICE_LOCATOR = 137,
+ SEC_OID_PKIX_REGCTRL_REGTOKEN = 138,
+ SEC_OID_PKIX_REGCTRL_AUTHENTICATOR = 139,
+ SEC_OID_PKIX_REGCTRL_PKIPUBINFO = 140,
+ SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS = 141,
+ SEC_OID_PKIX_REGCTRL_OLD_CERT_ID = 142,
+ SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY = 143,
+ SEC_OID_PKIX_REGINFO_UTF8_PAIRS = 144,
+ SEC_OID_PKIX_REGINFO_CERT_REQUEST = 145,
+ SEC_OID_EXT_KEY_USAGE_SERVER_AUTH = 146,
+ SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH = 147,
+ SEC_OID_EXT_KEY_USAGE_CODE_SIGN = 148,
+ SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT = 149,
+ SEC_OID_EXT_KEY_USAGE_TIME_STAMP = 150,
+ SEC_OID_OCSP_RESPONDER = 151,
+
+ /* Netscape Algorithm OIDs */
+ SEC_OID_NETSCAPE_SMIME_KEA = 152,
+
+ /* Skipjack OID -- ### mwelch temporary */
+ SEC_OID_FORTEZZA_SKIPJACK = 153,
+
+ /* PKCS 12 V2 oids */
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4 = 154,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4 = 155,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC = 156,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC = 157,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC = 158,
+ SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC = 159,
+ SEC_OID_PKCS12_SAFE_CONTENTS_ID = 160,
+ SEC_OID_PKCS12_PKCS8_SHROUDED_KEY_BAG_ID = 161,
+
+ SEC_OID_PKCS12_V1_KEY_BAG_ID = 162,
+ SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID = 163,
+ SEC_OID_PKCS12_V1_CERT_BAG_ID = 164,
+ SEC_OID_PKCS12_V1_CRL_BAG_ID = 165,
+ SEC_OID_PKCS12_V1_SECRET_BAG_ID = 166,
+ SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID = 167,
+ SEC_OID_PKCS9_X509_CERT = 168,
+ SEC_OID_PKCS9_SDSI_CERT = 169,
+ SEC_OID_PKCS9_X509_CRL = 170,
+ SEC_OID_PKCS9_FRIENDLY_NAME = 171,
+ SEC_OID_PKCS9_LOCAL_KEY_ID = 172,
+ SEC_OID_BOGUS_KEY_USAGE = 173,
+
+ /*Diffe Helman OIDS */
+ SEC_OID_X942_DIFFIE_HELMAN_KEY = 174,
+
+ /* Netscape other name types */
+ SEC_OID_NETSCAPE_NICKNAME = 175,
+
+ /* Cert Server OIDS */
+ SEC_OID_NETSCAPE_RECOVERY_REQUEST = 176,
+
+ /* New PSM certificate management OIDs */
+ SEC_OID_CERT_RENEWAL_LOCATOR = 177,
+ SEC_OID_NS_CERT_EXT_SCOPE_OF_USE = 178,
+
+ /* CMS (RFC2630) OIDs */
+ SEC_OID_CMS_EPHEMERAL_STATIC_DIFFIE_HELLMAN = 179,
+ SEC_OID_CMS_3DES_KEY_WRAP = 180,
+ SEC_OID_CMS_RC2_KEY_WRAP = 181,
+
+ /* SMIME attributes */
+ SEC_OID_SMIME_ENCRYPTION_KEY_PREFERENCE = 182,
+
+ /* AES OIDs */
+ SEC_OID_AES_128_ECB = 183,
+ SEC_OID_AES_128_CBC = 184,
+ SEC_OID_AES_192_ECB = 185,
+ SEC_OID_AES_192_CBC = 186,
+ SEC_OID_AES_256_ECB = 187,
+ SEC_OID_AES_256_CBC = 188,
+
+ SEC_OID_SDN702_DSA_SIGNATURE = 189,
+
+ SEC_OID_MS_SMIME_ENCRYPTION_KEY_PREFERENCE = 190,
+
+ SEC_OID_SHA256 = 191,
+ SEC_OID_SHA384 = 192,
+ SEC_OID_SHA512 = 193,
+
+ SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION = 194,
+ SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION = 195,
+ SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION = 196,
+
+ SEC_OID_AES_128_KEY_WRAP = 197,
+ SEC_OID_AES_192_KEY_WRAP = 198,
+ SEC_OID_AES_256_KEY_WRAP = 199,
+
+ /* Elliptic Curve Cryptography (ECC) OIDs */
+ SEC_OID_ANSIX962_EC_PUBLIC_KEY = 200,
+ SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE = 201,
+
+#define SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST \
+ SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE
+
+ /* ANSI X9.62 named elliptic curves (prime field) */
+ SEC_OID_ANSIX962_EC_PRIME192V1 = 202,
+ SEC_OID_ANSIX962_EC_PRIME192V2 = 203,
+ SEC_OID_ANSIX962_EC_PRIME192V3 = 204,
+ SEC_OID_ANSIX962_EC_PRIME239V1 = 205,
+ SEC_OID_ANSIX962_EC_PRIME239V2 = 206,
+ SEC_OID_ANSIX962_EC_PRIME239V3 = 207,
+ SEC_OID_ANSIX962_EC_PRIME256V1 = 208,
+
+ /* SECG named elliptic curves (prime field) */
+ SEC_OID_SECG_EC_SECP112R1 = 209,
+ SEC_OID_SECG_EC_SECP112R2 = 210,
+ SEC_OID_SECG_EC_SECP128R1 = 211,
+ SEC_OID_SECG_EC_SECP128R2 = 212,
+ SEC_OID_SECG_EC_SECP160K1 = 213,
+ SEC_OID_SECG_EC_SECP160R1 = 214,
+ SEC_OID_SECG_EC_SECP160R2 = 215,
+ SEC_OID_SECG_EC_SECP192K1 = 216,
+ /* SEC_OID_SECG_EC_SECP192R1 is SEC_OID_ANSIX962_EC_PRIME192V1 */
+ SEC_OID_SECG_EC_SECP224K1 = 217,
+ SEC_OID_SECG_EC_SECP224R1 = 218,
+ SEC_OID_SECG_EC_SECP256K1 = 219,
+ /* SEC_OID_SECG_EC_SECP256R1 is SEC_OID_ANSIX962_EC_PRIME256V1 */
+ SEC_OID_SECG_EC_SECP384R1 = 220,
+ SEC_OID_SECG_EC_SECP521R1 = 221,
+
+ /* ANSI X9.62 named elliptic curves (characteristic two field) */
+ SEC_OID_ANSIX962_EC_C2PNB163V1 = 222,
+ SEC_OID_ANSIX962_EC_C2PNB163V2 = 223,
+ SEC_OID_ANSIX962_EC_C2PNB163V3 = 224,
+ SEC_OID_ANSIX962_EC_C2PNB176V1 = 225,
+ SEC_OID_ANSIX962_EC_C2TNB191V1 = 226,
+ SEC_OID_ANSIX962_EC_C2TNB191V2 = 227,
+ SEC_OID_ANSIX962_EC_C2TNB191V3 = 228,
+ SEC_OID_ANSIX962_EC_C2ONB191V4 = 229,
+ SEC_OID_ANSIX962_EC_C2ONB191V5 = 230,
+ SEC_OID_ANSIX962_EC_C2PNB208W1 = 231,
+ SEC_OID_ANSIX962_EC_C2TNB239V1 = 232,
+ SEC_OID_ANSIX962_EC_C2TNB239V2 = 233,
+ SEC_OID_ANSIX962_EC_C2TNB239V3 = 234,
+ SEC_OID_ANSIX962_EC_C2ONB239V4 = 235,
+ SEC_OID_ANSIX962_EC_C2ONB239V5 = 236,
+ SEC_OID_ANSIX962_EC_C2PNB272W1 = 237,
+ SEC_OID_ANSIX962_EC_C2PNB304W1 = 238,
+ SEC_OID_ANSIX962_EC_C2TNB359V1 = 239,
+ SEC_OID_ANSIX962_EC_C2PNB368W1 = 240,
+ SEC_OID_ANSIX962_EC_C2TNB431R1 = 241,
+
+ /* SECG named elliptic curves (characteristic two field) */
+ SEC_OID_SECG_EC_SECT113R1 = 242,
+ SEC_OID_SECG_EC_SECT113R2 = 243,
+ SEC_OID_SECG_EC_SECT131R1 = 244,
+ SEC_OID_SECG_EC_SECT131R2 = 245,
+ SEC_OID_SECG_EC_SECT163K1 = 246,
+ SEC_OID_SECG_EC_SECT163R1 = 247,
+ SEC_OID_SECG_EC_SECT163R2 = 248,
+ SEC_OID_SECG_EC_SECT193R1 = 249,
+ SEC_OID_SECG_EC_SECT193R2 = 250,
+ SEC_OID_SECG_EC_SECT233K1 = 251,
+ SEC_OID_SECG_EC_SECT233R1 = 252,
+ SEC_OID_SECG_EC_SECT239K1 = 253,
+ SEC_OID_SECG_EC_SECT283K1 = 254,
+ SEC_OID_SECG_EC_SECT283R1 = 255,
+ SEC_OID_SECG_EC_SECT409K1 = 256,
+ SEC_OID_SECG_EC_SECT409R1 = 257,
+ SEC_OID_SECG_EC_SECT571K1 = 258,
+ SEC_OID_SECG_EC_SECT571R1 = 259,
+
+ SEC_OID_NETSCAPE_AOLSCREENNAME = 260,
+
+ SEC_OID_AVA_SURNAME = 261,
+ SEC_OID_AVA_SERIAL_NUMBER = 262,
+ SEC_OID_AVA_STREET_ADDRESS = 263,
+ SEC_OID_AVA_TITLE = 264,
+ SEC_OID_AVA_POSTAL_ADDRESS = 265,
+ SEC_OID_AVA_POSTAL_CODE = 266,
+ SEC_OID_AVA_POST_OFFICE_BOX = 267,
+ SEC_OID_AVA_GIVEN_NAME = 268,
+ SEC_OID_AVA_INITIALS = 269,
+ SEC_OID_AVA_GENERATION_QUALIFIER = 270,
+ SEC_OID_AVA_HOUSE_IDENTIFIER = 271,
+ SEC_OID_AVA_PSEUDONYM = 272,
+
+ /* More OIDs */
+ SEC_OID_PKIX_CA_ISSUERS = 273,
+ SEC_OID_PKCS9_EXTENSION_REQUEST = 274,
+
+ /* new EC Signature oids */
+ SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST = 275,
+ SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST = 276,
+ SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE = 277,
+ SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE = 278,
+ SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE = 279,
+ SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE = 280,
+
+ /* More id-ce and id-pe OIDs from RFC 3280 */
+ SEC_OID_X509_HOLD_INSTRUCTION_CODE = 281,
+ SEC_OID_X509_DELTA_CRL_INDICATOR = 282,
+ SEC_OID_X509_ISSUING_DISTRIBUTION_POINT = 283,
+ SEC_OID_X509_CERT_ISSUER = 284,
+ SEC_OID_X509_FRESHEST_CRL = 285,
+ SEC_OID_X509_INHIBIT_ANY_POLICY = 286,
+ SEC_OID_X509_SUBJECT_INFO_ACCESS = 287,
+
+ /* Camellia OIDs (RFC3657)*/
+ SEC_OID_CAMELLIA_128_CBC = 288,
+ SEC_OID_CAMELLIA_192_CBC = 289,
+ SEC_OID_CAMELLIA_256_CBC = 290,
+
+ /* PKCS 5 V2 OIDS */
+ SEC_OID_PKCS5_PBKDF2 = 291,
+ SEC_OID_PKCS5_PBES2 = 292,
+ SEC_OID_PKCS5_PBMAC1 = 293,
+ SEC_OID_HMAC_SHA1 = 294,
+ SEC_OID_HMAC_SHA224 = 295,
+ SEC_OID_HMAC_SHA256 = 296,
+ SEC_OID_HMAC_SHA384 = 297,
+ SEC_OID_HMAC_SHA512 = 298,
+
+ SEC_OID_PKIX_TIMESTAMPING = 299,
+ SEC_OID_PKIX_CA_REPOSITORY = 300,
+
+ SEC_OID_ISO_SHA1_WITH_RSA_SIGNATURE = 301,
+
+ SEC_OID_TOTAL
+} SECOidTag;
+
+#define SEC_OID_SECG_EC_SECP192R1 SEC_OID_ANSIX962_EC_PRIME192V1
+#define SEC_OID_SECG_EC_SECP256R1 SEC_OID_ANSIX962_EC_PRIME256V1
+#define SEC_OID_PKCS12_KEY_USAGE SEC_OID_X509_KEY_USAGE
+
+/* fake OID for DSS sign/verify */
+#define SEC_OID_SHA SEC_OID_MISS_DSS
+
+typedef enum {
+ INVALID_CERT_EXTENSION = 0,
+ UNSUPPORTED_CERT_EXTENSION = 1,
+ SUPPORTED_CERT_EXTENSION = 2
+} SECSupportExtenTag;
+
+struct SECOidDataStr {
+ SECItem oid;
+ SECOidTag offset;
+ const char * desc;
+ unsigned long mechanism;
+ SECSupportExtenTag supportedExtension;
+ /* only used for x.509 v3 extensions, so
+ that we can print the names of those
+ extensions that we don't even support */
+};
+
+#endif /* _SECOIDT_H_ */
diff --git a/security/nss/lib/util/secplcy.c b/security/nss/lib/util/secplcy.c
new file mode 100644
index 000000000..f2b66fb53
--- /dev/null
+++ b/security/nss/lib/util/secplcy.c
@@ -0,0 +1,117 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "secplcy.h"
+#include "prmem.h"
+
+SECCipherFind *sec_CipherFindInit(PRBool onlyAllowed,
+ secCPStruct *policy,
+ long *ciphers)
+{
+ SECCipherFind *find = PR_NEWZAP(SECCipherFind);
+ if (find)
+ {
+ find->policy = policy;
+ find->ciphers = ciphers;
+ find->onlyAllowed = onlyAllowed;
+ find->index = -1;
+ }
+ return find;
+}
+
+long sec_CipherFindNext(SECCipherFind *find)
+{
+ char *policy;
+ long rv = -1;
+ secCPStruct *policies = (secCPStruct *) find->policy;
+ long *ciphers = (long *) find->ciphers;
+ long numCiphers = policies->num_ciphers;
+
+ find->index++;
+ while((find->index < numCiphers) && (rv == -1))
+ {
+ /* Translate index to cipher. */
+ rv = ciphers[find->index];
+
+ /* If we're only looking for allowed ciphers, and if this
+ cipher isn't allowed, loop around.*/
+ if (find->onlyAllowed)
+ {
+ /* Find the appropriate policy flag. */
+ policy = (&(policies->begin_ciphers)) + find->index + 1;
+
+ /* If this cipher isn't allowed by policy, continue. */
+ if (! (*policy))
+ {
+ rv = -1;
+ find->index++;
+ }
+ }
+ }
+
+ return rv;
+}
+
+char sec_IsCipherAllowed(long cipher, secCPStruct *policies,
+ long *ciphers)
+{
+ char result = SEC_CIPHER_NOT_ALLOWED; /* our default answer */
+ long numCiphers = policies->num_ciphers;
+ char *policy;
+ int i;
+
+ /* Convert the cipher number into a policy flag location. */
+ for (i=0, policy=(&(policies->begin_ciphers) + 1);
+ i<numCiphers;
+ i++, policy++)
+ {
+ if (cipher == ciphers[i])
+ break;
+ }
+
+ if (i < numCiphers)
+ {
+ /* Found the cipher, get the policy value. */
+ result = *policy;
+ }
+
+ return result;
+}
+
+void sec_CipherFindEnd(SECCipherFind *find)
+{
+ PR_FREEIF(find);
+}
diff --git a/security/nss/lib/util/secplcy.h b/security/nss/lib/util/secplcy.h
new file mode 100644
index 000000000..758ee13f7
--- /dev/null
+++ b/security/nss/lib/util/secplcy.h
@@ -0,0 +1,138 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef __secplcy_h__
+#define __secplcy_h__
+
+#include "utilrename.h"
+
+#include "prtypes.h"
+
+/*
+** Cipher policy enforcement. This code isn't very pretty, but it accomplishes
+** the purpose of obscuring policy information from potential fortifiers. :-)
+**
+** The following routines are generic and intended for anywhere where cipher
+** policy enforcement is to be done, e.g. SSL and PKCS7&12.
+*/
+
+#define SEC_CIPHER_NOT_ALLOWED 0
+#define SEC_CIPHER_ALLOWED 1
+#define SEC_CIPHER_RESTRICTED 2 /* cipher is allowed in limited cases
+ e.g. step-up */
+
+/* The length of the header string for each cipher table.
+ (It's the same regardless of whether we're using md5 strings or not.) */
+#define SEC_POLICY_HEADER_LENGTH 48
+
+/* If we're testing policy stuff, we may want to use the plaintext version */
+#define SEC_POLICY_USE_MD5_STRINGS 1
+
+#define SEC_POLICY_THIS_IS_THE \
+ "\x2a\x3a\x51\xbf\x2f\x71\xb7\x73\xaa\xca\x6b\x57\x70\xcd\xc8\x9f"
+#define SEC_POLICY_STRING_FOR_THE \
+ "\x97\x15\xe2\x70\xd2\x8a\xde\xa9\xe7\xa7\x6a\xe2\x83\xe5\xb1\xf6"
+#define SEC_POLICY_SSL_TAIL \
+ "\x70\x16\x25\xc0\x2a\xb2\x4a\xca\xb6\x67\xb1\x89\x20\xdf\x87\xca"
+#define SEC_POLICY_SMIME_TAIL \
+ "\xdf\xd4\xe7\x2a\xeb\xc4\x1b\xb5\xd8\xe5\xe0\x2a\x16\x9f\xc4\xb9"
+#define SEC_POLICY_PKCS12_TAIL \
+ "\x1c\xf8\xa4\x85\x4a\xc6\x8a\xfe\xe6\xca\x03\x72\x50\x1c\xe2\xc8"
+
+#if defined(SEC_POLICY_USE_MD5_STRINGS)
+
+/* We're not testing.
+ Use md5 checksums of the strings. */
+
+#define SEC_POLICY_SSL_HEADER \
+ SEC_POLICY_THIS_IS_THE SEC_POLICY_STRING_FOR_THE SEC_POLICY_SSL_TAIL
+
+#define SEC_POLICY_SMIME_HEADER \
+ SEC_POLICY_THIS_IS_THE SEC_POLICY_STRING_FOR_THE SEC_POLICY_SMIME_TAIL
+
+#define SEC_POLICY_PKCS12_HEADER \
+ SEC_POLICY_THIS_IS_THE SEC_POLICY_STRING_FOR_THE SEC_POLICY_PKCS12_TAIL
+
+#else
+
+/* We're testing.
+ Use plaintext versions of the strings, for testing purposes. */
+#define SEC_POLICY_SSL_HEADER \
+ "This is the string for the SSL policy table. "
+#define SEC_POLICY_SMIME_HEADER \
+ "This is the string for the PKCS7 policy table. "
+#define SEC_POLICY_PKCS12_HEADER \
+ "This is the string for the PKCS12 policy table. "
+
+#endif
+
+/* Local cipher tables have to have these members at the top. */
+typedef struct _sec_cp_struct
+{
+ char policy_string[SEC_POLICY_HEADER_LENGTH];
+ long unused; /* placeholder for max keybits in pkcs12 struct */
+ char num_ciphers;
+ char begin_ciphers;
+ /* cipher policy settings follow. each is a char. */
+} secCPStruct;
+
+struct SECCipherFindStr
+{
+ /* (policy) and (ciphers) are opaque to the outside world */
+ void *policy;
+ void *ciphers;
+ long index;
+ PRBool onlyAllowed;
+};
+
+typedef struct SECCipherFindStr SECCipherFind;
+
+SEC_BEGIN_PROTOS
+
+SECCipherFind *sec_CipherFindInit(PRBool onlyAllowed,
+ secCPStruct *policy,
+ long *ciphers);
+
+long sec_CipherFindNext(SECCipherFind *find);
+
+char sec_IsCipherAllowed(long cipher, secCPStruct *policies,
+ long *ciphers);
+
+void sec_CipherFindEnd(SECCipherFind *find);
+
+SEC_END_PROTOS
+
+#endif /* __SECPLCY_H__ */
diff --git a/security/nss/lib/util/secport.c b/security/nss/lib/util/secport.c
new file mode 100644
index 000000000..430b1ca17
--- /dev/null
+++ b/security/nss/lib/util/secport.c
@@ -0,0 +1,667 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * secport.c - portability interfaces for security libraries
+ *
+ * This file abstracts out libc functionality that libsec depends on
+ *
+ * NOTE - These are not public interfaces
+ *
+ * $Id$
+ */
+
+#include "seccomon.h"
+#include "prmem.h"
+#include "prerror.h"
+#include "plarena.h"
+#include "secerr.h"
+#include "prmon.h"
+#include "nssilock.h"
+#include "secport.h"
+#include "prvrsion.h"
+#include "prenv.h"
+
+#ifdef DEBUG
+#define THREADMARK
+#endif /* DEBUG */
+
+#ifdef THREADMARK
+#include "prthread.h"
+#endif /* THREADMARK */
+
+#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS)
+#include <stdlib.h>
+#else
+#include "wtypes.h"
+#endif
+
+#define SET_ERROR_CODE /* place holder for code to set PR error code. */
+
+#ifdef THREADMARK
+typedef struct threadmark_mark_str {
+ struct threadmark_mark_str *next;
+ void *mark;
+} threadmark_mark;
+
+#endif /* THREADMARK */
+
+/* The value of this magic must change each time PORTArenaPool changes. */
+#define ARENAPOOL_MAGIC 0xB8AC9BDF
+
+typedef struct PORTArenaPool_str {
+ PLArenaPool arena;
+ PRUint32 magic;
+ PRLock * lock;
+#ifdef THREADMARK
+ PRThread *marking_thread;
+ threadmark_mark *first_mark;
+#endif
+} PORTArenaPool;
+
+
+/* count of allocation failures. */
+unsigned long port_allocFailures;
+
+/* locations for registering Unicode conversion functions.
+ * XXX is this the appropriate location? or should they be
+ * moved to client/server specific locations?
+ */
+PORTCharConversionFunc ucs4Utf8ConvertFunc;
+PORTCharConversionFunc ucs2Utf8ConvertFunc;
+PORTCharConversionWSwapFunc ucs2AsciiConvertFunc;
+
+void *
+PORT_Alloc(size_t bytes)
+{
+ void *rv;
+
+ /* Always allocate a non-zero amount of bytes */
+ rv = (void *)PR_Malloc(bytes ? bytes : 1);
+ if (!rv) {
+ ++port_allocFailures;
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+ return rv;
+}
+
+void *
+PORT_Realloc(void *oldptr, size_t bytes)
+{
+ void *rv;
+
+ rv = (void *)PR_Realloc(oldptr, bytes);
+ if (!rv) {
+ ++port_allocFailures;
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+ return rv;
+}
+
+void *
+PORT_ZAlloc(size_t bytes)
+{
+ void *rv;
+
+ /* Always allocate a non-zero amount of bytes */
+ rv = (void *)PR_Calloc(1, bytes ? bytes : 1);
+ if (!rv) {
+ ++port_allocFailures;
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+ return rv;
+}
+
+void
+PORT_Free(void *ptr)
+{
+ if (ptr) {
+ PR_Free(ptr);
+ }
+}
+
+void
+PORT_ZFree(void *ptr, size_t len)
+{
+ if (ptr) {
+ memset(ptr, 0, len);
+ PR_Free(ptr);
+ }
+}
+
+char *
+PORT_Strdup(const char *str)
+{
+ size_t len = PORT_Strlen(str)+1;
+ char *newstr;
+
+ newstr = (char *)PORT_Alloc(len);
+ if (newstr) {
+ PORT_Memcpy(newstr, str, len);
+ }
+ return newstr;
+}
+
+void
+PORT_SetError(int value)
+{
+#ifdef DEBUG_jp96085
+ PORT_Assert(value != SEC_ERROR_REUSED_ISSUER_AND_SERIAL);
+#endif
+ PR_SetError(value, 0);
+ return;
+}
+
+int
+PORT_GetError(void)
+{
+ return(PR_GetError());
+}
+
+/********************* Arena code follows *****************************/
+
+PLArenaPool *
+PORT_NewArena(unsigned long chunksize)
+{
+ PORTArenaPool *pool;
+
+ pool = PORT_ZNew(PORTArenaPool);
+ if (!pool) {
+ return NULL;
+ }
+ pool->magic = ARENAPOOL_MAGIC;
+ pool->lock = PZ_NewLock(nssILockArena);
+ if (!pool->lock) {
+ ++port_allocFailures;
+ PORT_Free(pool);
+ return NULL;
+ }
+ PL_InitArenaPool(&pool->arena, "security", chunksize, sizeof(double));
+ return(&pool->arena);
+}
+
+#define MAX_SIZE 0x7fffffffUL
+
+void *
+PORT_ArenaAlloc(PLArenaPool *arena, size_t size)
+{
+ void *p = NULL;
+
+ PORTArenaPool *pool = (PORTArenaPool *)arena;
+
+ if (size <= 0) {
+ size = 1;
+ }
+
+ if (size > MAX_SIZE) {
+ /* you lose. */
+ } else
+ /* Is it one of ours? Assume so and check the magic */
+ if (ARENAPOOL_MAGIC == pool->magic ) {
+ PZ_Lock(pool->lock);
+#ifdef THREADMARK
+ /* Most likely one of ours. Is there a thread id? */
+ if (pool->marking_thread &&
+ pool->marking_thread != PR_GetCurrentThread() ) {
+ /* Another thread holds a mark in this arena */
+ PZ_Unlock(pool->lock);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ PORT_Assert(0);
+ return NULL;
+ } /* tid != null */
+#endif /* THREADMARK */
+ PL_ARENA_ALLOCATE(p, arena, size);
+ PZ_Unlock(pool->lock);
+ } else {
+ PL_ARENA_ALLOCATE(p, arena, size);
+ }
+
+ if (!p) {
+ ++port_allocFailures;
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ }
+
+ return(p);
+}
+
+void *
+PORT_ArenaZAlloc(PLArenaPool *arena, size_t size)
+{
+ void *p;
+
+ if (size <= 0)
+ size = 1;
+
+ p = PORT_ArenaAlloc(arena, size);
+
+ if (p) {
+ PORT_Memset(p, 0, size);
+ }
+
+ return(p);
+}
+
+/*
+ * If zero is true, zeroize the arena memory before freeing it.
+ */
+void
+PORT_FreeArena(PLArenaPool *arena, PRBool zero)
+{
+ PORTArenaPool *pool = (PORTArenaPool *)arena;
+ PRLock * lock = (PRLock *)0;
+ size_t len = sizeof *arena;
+ extern const PRVersionDescription * libVersionPoint(void);
+ static const PRVersionDescription * pvd;
+ static PRBool doFreeArenaPool = PR_FALSE;
+
+ if (ARENAPOOL_MAGIC == pool->magic ) {
+ len = sizeof *pool;
+ lock = pool->lock;
+ PZ_Lock(lock);
+ }
+ if (!pvd) {
+ /* Each of NSPR's DLLs has a function libVersionPoint().
+ ** We could do a lot of extra work to be sure we're calling the
+ ** one in the DLL that holds PR_FreeArenaPool, but instead we
+ ** rely on the fact that ALL NSPR DLLs in the same directory
+ ** must be from the same release, and we call which ever one we get.
+ */
+ /* no need for thread protection here */
+ pvd = libVersionPoint();
+ if ((pvd->vMajor > 4) ||
+ (pvd->vMajor == 4 && pvd->vMinor > 1) ||
+ (pvd->vMajor == 4 && pvd->vMinor == 1 && pvd->vPatch >= 1)) {
+ const char *ev = PR_GetEnv("NSS_DISABLE_ARENA_FREE_LIST");
+ if (!ev) doFreeArenaPool = PR_TRUE;
+ }
+ }
+ if (zero) {
+ PLArena *a;
+ for (a = arena->first.next; a; a = a->next) {
+ PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
+ memset((void *)a->base, 0, a->avail - a->base);
+ }
+ }
+ if (doFreeArenaPool) {
+ PL_FreeArenaPool(arena);
+ } else {
+ PL_FinishArenaPool(arena);
+ }
+ PORT_ZFree(arena, len);
+ if (lock) {
+ PZ_Unlock(lock);
+ PZ_DestroyLock(lock);
+ }
+}
+
+void *
+PORT_ArenaGrow(PLArenaPool *arena, void *ptr, size_t oldsize, size_t newsize)
+{
+ PORTArenaPool *pool = (PORTArenaPool *)arena;
+ PORT_Assert(newsize >= oldsize);
+
+ if (ARENAPOOL_MAGIC == pool->magic ) {
+ PZ_Lock(pool->lock);
+ /* Do we do a THREADMARK check here? */
+ PL_ARENA_GROW(ptr, arena, oldsize, ( newsize - oldsize ) );
+ PZ_Unlock(pool->lock);
+ } else {
+ PL_ARENA_GROW(ptr, arena, oldsize, ( newsize - oldsize ) );
+ }
+
+ return(ptr);
+}
+
+void *
+PORT_ArenaMark(PLArenaPool *arena)
+{
+ void * result;
+
+ PORTArenaPool *pool = (PORTArenaPool *)arena;
+ if (ARENAPOOL_MAGIC == pool->magic ) {
+ PZ_Lock(pool->lock);
+#ifdef THREADMARK
+ {
+ threadmark_mark *tm, **pw;
+ PRThread * currentThread = PR_GetCurrentThread();
+
+ if (! pool->marking_thread ) {
+ /* First mark */
+ pool->marking_thread = currentThread;
+ } else if (currentThread != pool->marking_thread ) {
+ PZ_Unlock(pool->lock);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ PORT_Assert(0);
+ return NULL;
+ }
+
+ result = PL_ARENA_MARK(arena);
+ PL_ARENA_ALLOCATE(tm, arena, sizeof(threadmark_mark));
+ if (!tm) {
+ PZ_Unlock(pool->lock);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ return NULL;
+ }
+
+ tm->mark = result;
+ tm->next = (threadmark_mark *)NULL;
+
+ pw = &pool->first_mark;
+ while( *pw ) {
+ pw = &(*pw)->next;
+ }
+
+ *pw = tm;
+ }
+#else /* THREADMARK */
+ result = PL_ARENA_MARK(arena);
+#endif /* THREADMARK */
+ PZ_Unlock(pool->lock);
+ } else {
+ /* a "pure" NSPR arena */
+ result = PL_ARENA_MARK(arena);
+ }
+ return result;
+}
+
+static void
+port_ArenaZeroAfterMark(PLArenaPool *arena, void *mark)
+{
+ PLArena *a = arena->current;
+ if (a->base <= (PRUword)mark && (PRUword)mark <= a->avail) {
+ /* fast path: mark falls in the current arena */
+ memset(mark, 0, a->avail - (PRUword)mark);
+ } else {
+ /* slow path: need to find the arena that mark falls in */
+ for (a = arena->first.next; a; a = a->next) {
+ PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
+ if (a->base <= (PRUword)mark && (PRUword)mark <= a->avail) {
+ memset(mark, 0, a->avail - (PRUword)mark);
+ a = a->next;
+ break;
+ }
+ }
+ for (; a; a = a->next) {
+ PR_ASSERT(a->base <= a->avail && a->avail <= a->limit);
+ memset((void *)a->base, 0, a->avail - a->base);
+ }
+ }
+}
+
+static void
+port_ArenaRelease(PLArenaPool *arena, void *mark, PRBool zero)
+{
+ PORTArenaPool *pool = (PORTArenaPool *)arena;
+ if (ARENAPOOL_MAGIC == pool->magic ) {
+ PZ_Lock(pool->lock);
+#ifdef THREADMARK
+ {
+ threadmark_mark **pw, *tm;
+
+ if (PR_GetCurrentThread() != pool->marking_thread ) {
+ PZ_Unlock(pool->lock);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ PORT_Assert(0);
+ return /* no error indication available */ ;
+ }
+
+ pw = &pool->first_mark;
+ while( *pw && (mark != (*pw)->mark) ) {
+ pw = &(*pw)->next;
+ }
+
+ if (! *pw ) {
+ /* bad mark */
+ PZ_Unlock(pool->lock);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ PORT_Assert(0);
+ return /* no error indication available */ ;
+ }
+
+ tm = *pw;
+ *pw = (threadmark_mark *)NULL;
+
+ if (zero) {
+ port_ArenaZeroAfterMark(arena, mark);
+ }
+ PL_ARENA_RELEASE(arena, mark);
+
+ if (! pool->first_mark ) {
+ pool->marking_thread = (PRThread *)NULL;
+ }
+ }
+#else /* THREADMARK */
+ if (zero) {
+ port_ArenaZeroAfterMark(arena, mark);
+ }
+ PL_ARENA_RELEASE(arena, mark);
+#endif /* THREADMARK */
+ PZ_Unlock(pool->lock);
+ } else {
+ if (zero) {
+ port_ArenaZeroAfterMark(arena, mark);
+ }
+ PL_ARENA_RELEASE(arena, mark);
+ }
+}
+
+void
+PORT_ArenaRelease(PLArenaPool *arena, void *mark)
+{
+ port_ArenaRelease(arena, mark, PR_FALSE);
+}
+
+/*
+ * Zeroize the arena memory before releasing it.
+ */
+void
+PORT_ArenaZRelease(PLArenaPool *arena, void *mark)
+{
+ port_ArenaRelease(arena, mark, PR_TRUE);
+}
+
+void
+PORT_ArenaUnmark(PLArenaPool *arena, void *mark)
+{
+#ifdef THREADMARK
+ PORTArenaPool *pool = (PORTArenaPool *)arena;
+ if (ARENAPOOL_MAGIC == pool->magic ) {
+ threadmark_mark **pw, *tm;
+
+ PZ_Lock(pool->lock);
+
+ if (PR_GetCurrentThread() != pool->marking_thread ) {
+ PZ_Unlock(pool->lock);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ PORT_Assert(0);
+ return /* no error indication available */ ;
+ }
+
+ pw = &pool->first_mark;
+ while( ((threadmark_mark *)NULL != *pw) && (mark != (*pw)->mark) ) {
+ pw = &(*pw)->next;
+ }
+
+ if ((threadmark_mark *)NULL == *pw ) {
+ /* bad mark */
+ PZ_Unlock(pool->lock);
+ PORT_SetError(SEC_ERROR_NO_MEMORY);
+ PORT_Assert(0);
+ return /* no error indication available */ ;
+ }
+
+ tm = *pw;
+ *pw = (threadmark_mark *)NULL;
+
+ if (! pool->first_mark ) {
+ pool->marking_thread = (PRThread *)NULL;
+ }
+
+ PZ_Unlock(pool->lock);
+ }
+#endif /* THREADMARK */
+}
+
+char *
+PORT_ArenaStrdup(PLArenaPool *arena, const char *str) {
+ int len = PORT_Strlen(str)+1;
+ char *newstr;
+
+ newstr = (char*)PORT_ArenaAlloc(arena,len);
+ if (newstr) {
+ PORT_Memcpy(newstr,str,len);
+ }
+ return newstr;
+}
+
+/********************** end of arena functions ***********************/
+
+/****************** unicode conversion functions ***********************/
+/*
+ * NOTE: These conversion functions all assume that the multibyte
+ * characters are going to be in NETWORK BYTE ORDER, not host byte
+ * order. This is because the only time we deal with UCS-2 and UCS-4
+ * are when the data was received from or is going to be sent out
+ * over the wire (in, e.g. certificates).
+ */
+
+void
+PORT_SetUCS4_UTF8ConversionFunction(PORTCharConversionFunc convFunc)
+{
+ ucs4Utf8ConvertFunc = convFunc;
+}
+
+void
+PORT_SetUCS2_ASCIIConversionFunction(PORTCharConversionWSwapFunc convFunc)
+{
+ ucs2AsciiConvertFunc = convFunc;
+}
+
+void
+PORT_SetUCS2_UTF8ConversionFunction(PORTCharConversionFunc convFunc)
+{
+ ucs2Utf8ConvertFunc = convFunc;
+}
+
+PRBool
+PORT_UCS4_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
+ unsigned int inBufLen, unsigned char *outBuf,
+ unsigned int maxOutBufLen, unsigned int *outBufLen)
+{
+ if(!ucs4Utf8ConvertFunc) {
+ return sec_port_ucs4_utf8_conversion_function(toUnicode,
+ inBuf, inBufLen, outBuf, maxOutBufLen, outBufLen);
+ }
+
+ return (*ucs4Utf8ConvertFunc)(toUnicode, inBuf, inBufLen, outBuf,
+ maxOutBufLen, outBufLen);
+}
+
+PRBool
+PORT_UCS2_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
+ unsigned int inBufLen, unsigned char *outBuf,
+ unsigned int maxOutBufLen, unsigned int *outBufLen)
+{
+ if(!ucs2Utf8ConvertFunc) {
+ return sec_port_ucs2_utf8_conversion_function(toUnicode,
+ inBuf, inBufLen, outBuf, maxOutBufLen, outBufLen);
+ }
+
+ return (*ucs2Utf8ConvertFunc)(toUnicode, inBuf, inBufLen, outBuf,
+ maxOutBufLen, outBufLen);
+}
+
+PRBool
+PORT_ISO88591_UTF8Conversion(const unsigned char *inBuf,
+ unsigned int inBufLen, unsigned char *outBuf,
+ unsigned int maxOutBufLen, unsigned int *outBufLen)
+{
+ return sec_port_iso88591_utf8_conversion_function(inBuf, inBufLen,
+ outBuf, maxOutBufLen, outBufLen);
+}
+
+PRBool
+PORT_UCS2_ASCIIConversion(PRBool toUnicode, unsigned char *inBuf,
+ unsigned int inBufLen, unsigned char *outBuf,
+ unsigned int maxOutBufLen, unsigned int *outBufLen,
+ PRBool swapBytes)
+{
+ if(!ucs2AsciiConvertFunc) {
+ return PR_FALSE;
+ }
+
+ return (*ucs2AsciiConvertFunc)(toUnicode, inBuf, inBufLen, outBuf,
+ maxOutBufLen, outBufLen, swapBytes);
+}
+
+
+/* Portable putenv. Creates/replaces an environment variable of the form
+ * envVarName=envValue
+ */
+int
+NSS_PutEnv(const char * envVarName, const char * envValue)
+{
+#ifdef _WIN32_WCE
+ return SECFailure;
+#else
+ SECStatus result = SECSuccess;
+ char * encoded;
+ int putEnvFailed;
+#ifdef _WIN32
+ PRBool setOK;
+
+ setOK = SetEnvironmentVariable(envVarName, envValue);
+ if (!setOK) {
+ SET_ERROR_CODE
+ return SECFailure;
+ }
+#endif
+
+ encoded = (char *)PORT_ZAlloc(strlen(envVarName) + 2 + strlen(envValue));
+ strcpy(encoded, envVarName);
+ strcat(encoded, "=");
+ strcat(encoded, envValue);
+
+ putEnvFailed = putenv(encoded); /* adopt. */
+ if (putEnvFailed) {
+ SET_ERROR_CODE
+ result = SECFailure;
+ PORT_Free(encoded);
+ }
+ return result;
+#endif
+}
+
diff --git a/security/nss/lib/util/secport.h b/security/nss/lib/util/secport.h
new file mode 100644
index 000000000..923c09b0f
--- /dev/null
+++ b/security/nss/lib/util/secport.h
@@ -0,0 +1,253 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * secport.h - portability interfaces for security libraries
+ *
+ * $Id$
+ */
+
+#ifndef _SECPORT_H_
+#define _SECPORT_H_
+
+#include "utilrename.h"
+
+/*
+ * define XP_WIN, XP_BEOS, or XP_UNIX, in case they are not defined
+ * by anyone else
+ */
+#ifdef _WINDOWS
+# ifndef XP_WIN
+# define XP_WIN
+# endif
+#if defined(_WIN32) || defined(WIN32)
+# ifndef XP_WIN32
+# define XP_WIN32
+# endif
+#else
+# ifndef XP_WIN16
+# define XP_WIN16
+# endif
+#endif
+#endif
+
+#ifdef __BEOS__
+# ifndef XP_BEOS
+# define XP_BEOS
+# endif
+#endif
+
+#ifdef unix
+# ifndef XP_UNIX
+# define XP_UNIX
+# endif
+#endif
+
+#if defined(__WATCOMC__) || defined(__WATCOM_CPLUSPLUS__)
+#include "watcomfx.h"
+#endif
+
+#if defined(_WIN32_WCE)
+#include <windef.h>
+#include <types.h>
+#else
+#include <sys/types.h>
+#endif
+
+#include <ctype.h>
+#include <string.h>
+#if defined(_WIN32_WCE)
+#include <stdlib.h> /* WinCE puts some stddef symbols here. */
+#else
+#include <stddef.h>
+#endif
+#include <stdlib.h>
+#include "prtypes.h"
+#include "prlog.h" /* for PR_ASSERT */
+#include "plarena.h"
+#include "plstr.h"
+
+/*
+ * HACK for NSS 2.8 to allow Admin to compile without source changes.
+ */
+#ifndef SEC_BEGIN_PROTOS
+#include "seccomon.h"
+#endif
+
+SEC_BEGIN_PROTOS
+
+extern void *PORT_Alloc(size_t len);
+extern void *PORT_Realloc(void *old, size_t len);
+extern void *PORT_AllocBlock(size_t len);
+extern void *PORT_ReallocBlock(void *old, size_t len);
+extern void PORT_FreeBlock(void *ptr);
+extern void *PORT_ZAlloc(size_t len);
+extern void PORT_Free(void *ptr);
+extern void PORT_ZFree(void *ptr, size_t len);
+extern char *PORT_Strdup(const char *s);
+extern time_t PORT_Time(void);
+extern void PORT_SetError(int value);
+extern int PORT_GetError(void);
+
+extern PLArenaPool *PORT_NewArena(unsigned long chunksize);
+extern void *PORT_ArenaAlloc(PLArenaPool *arena, size_t size);
+extern void *PORT_ArenaZAlloc(PLArenaPool *arena, size_t size);
+extern void PORT_FreeArena(PLArenaPool *arena, PRBool zero);
+extern void *PORT_ArenaGrow(PLArenaPool *arena, void *ptr,
+ size_t oldsize, size_t newsize);
+extern void *PORT_ArenaMark(PLArenaPool *arena);
+extern void PORT_ArenaRelease(PLArenaPool *arena, void *mark);
+extern void PORT_ArenaZRelease(PLArenaPool *arena, void *mark);
+extern void PORT_ArenaUnmark(PLArenaPool *arena, void *mark);
+extern char *PORT_ArenaStrdup(PLArenaPool *arena, const char *str);
+
+SEC_END_PROTOS
+
+#define PORT_Assert PR_ASSERT
+#define PORT_ZNew(type) (type*)PORT_ZAlloc(sizeof(type))
+#define PORT_New(type) (type*)PORT_Alloc(sizeof(type))
+#define PORT_ArenaNew(poolp, type) \
+ (type*) PORT_ArenaAlloc(poolp, sizeof(type))
+#define PORT_ArenaZNew(poolp, type) \
+ (type*) PORT_ArenaZAlloc(poolp, sizeof(type))
+#define PORT_NewArray(type, num) \
+ (type*) PORT_Alloc (sizeof(type)*(num))
+#define PORT_ZNewArray(type, num) \
+ (type*) PORT_ZAlloc (sizeof(type)*(num))
+#define PORT_ArenaNewArray(poolp, type, num) \
+ (type*) PORT_ArenaAlloc (poolp, sizeof(type)*(num))
+#define PORT_ArenaZNewArray(poolp, type, num) \
+ (type*) PORT_ArenaZAlloc (poolp, sizeof(type)*(num))
+
+/* Please, keep these defines sorted alphabetically. Thanks! */
+
+#define PORT_Atoi atoi
+
+#define PORT_Memcmp memcmp
+#define PORT_Memcpy memcpy
+#ifndef SUNOS4
+#define PORT_Memmove memmove
+#else /*SUNOS4*/
+#define PORT_Memmove(s,ct,n) bcopy ((ct), (s), (n))
+#endif/*SUNOS4*/
+#define PORT_Memset memset
+
+#define PORT_Strcasecmp PL_strcasecmp
+#define PORT_Strcat strcat
+#define PORT_Strchr strchr
+#define PORT_Strrchr strrchr
+#define PORT_Strcmp strcmp
+#define PORT_Strcpy strcpy
+#define PORT_Strlen(s) strlen(s)
+#define PORT_Strncasecmp PL_strncasecmp
+#define PORT_Strncat strncat
+#define PORT_Strncmp strncmp
+#define PORT_Strncpy strncpy
+#define PORT_Strpbrk strpbrk
+#define PORT_Strstr strstr
+#define PORT_Strtok strtok
+
+#define PORT_Tolower tolower
+
+typedef PRBool (PR_CALLBACK * PORTCharConversionWSwapFunc) (PRBool toUnicode,
+ unsigned char *inBuf, unsigned int inBufLen,
+ unsigned char *outBuf, unsigned int maxOutBufLen,
+ unsigned int *outBufLen, PRBool swapBytes);
+
+typedef PRBool (PR_CALLBACK * PORTCharConversionFunc) (PRBool toUnicode,
+ unsigned char *inBuf, unsigned int inBufLen,
+ unsigned char *outBuf, unsigned int maxOutBufLen,
+ unsigned int *outBufLen);
+
+SEC_BEGIN_PROTOS
+
+void PORT_SetUCS4_UTF8ConversionFunction(PORTCharConversionFunc convFunc);
+void PORT_SetUCS2_ASCIIConversionFunction(PORTCharConversionWSwapFunc convFunc);
+PRBool PORT_UCS4_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
+ unsigned int inBufLen, unsigned char *outBuf,
+ unsigned int maxOutBufLen, unsigned int *outBufLen);
+PRBool PORT_UCS2_ASCIIConversion(PRBool toUnicode, unsigned char *inBuf,
+ unsigned int inBufLen, unsigned char *outBuf,
+ unsigned int maxOutBufLen, unsigned int *outBufLen,
+ PRBool swapBytes);
+void PORT_SetUCS2_UTF8ConversionFunction(PORTCharConversionFunc convFunc);
+PRBool PORT_UCS2_UTF8Conversion(PRBool toUnicode, unsigned char *inBuf,
+ unsigned int inBufLen, unsigned char *outBuf,
+ unsigned int maxOutBufLen, unsigned int *outBufLen);
+
+/* One-way conversion from ISO-8859-1 to UTF-8 */
+PRBool PORT_ISO88591_UTF8Conversion(const unsigned char *inBuf,
+ unsigned int inBufLen, unsigned char *outBuf,
+ unsigned int maxOutBufLen, unsigned int *outBufLen);
+
+extern PRBool
+sec_port_ucs4_utf8_conversion_function
+(
+ PRBool toUnicode,
+ unsigned char *inBuf,
+ unsigned int inBufLen,
+ unsigned char *outBuf,
+ unsigned int maxOutBufLen,
+ unsigned int *outBufLen
+);
+
+extern PRBool
+sec_port_ucs2_utf8_conversion_function
+(
+ PRBool toUnicode,
+ unsigned char *inBuf,
+ unsigned int inBufLen,
+ unsigned char *outBuf,
+ unsigned int maxOutBufLen,
+ unsigned int *outBufLen
+);
+
+/* One-way conversion from ISO-8859-1 to UTF-8 */
+extern PRBool
+sec_port_iso88591_utf8_conversion_function
+(
+ const unsigned char *inBuf,
+ unsigned int inBufLen,
+ unsigned char *outBuf,
+ unsigned int maxOutBufLen,
+ unsigned int *outBufLen
+);
+
+extern int NSS_PutEnv(const char * envVarName, const char * envValue);
+
+SEC_END_PROTOS
+
+#endif /* _SECPORT_H_ */
diff --git a/security/nss/lib/util/sectime.c b/security/nss/lib/util/sectime.c
new file mode 100644
index 000000000..cf4c526fb
--- /dev/null
+++ b/security/nss/lib/util/sectime.c
@@ -0,0 +1,194 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "prlong.h"
+#include "prtime.h"
+#include "secder.h"
+#include "secitem.h"
+#include "secerr.h"
+
+static const PRTime January1st2050 = LL_INIT(0x0008f81e, 0x1b098000);
+
+static char *DecodeUTCTime2FormattedAscii (SECItem *utcTimeDER, char *format);
+static char *DecodeGeneralizedTime2FormattedAscii (SECItem *generalizedTimeDER, char *format);
+
+/* convert DER utc time to ascii time string */
+char *
+DER_UTCTimeToAscii(SECItem *utcTime)
+{
+ return (DecodeUTCTime2FormattedAscii (utcTime, "%a %b %d %H:%M:%S %Y"));
+}
+
+/* convert DER utc time to ascii time string, only include day, not time */
+char *
+DER_UTCDayToAscii(SECItem *utctime)
+{
+ return (DecodeUTCTime2FormattedAscii (utctime, "%a %b %d, %Y"));
+}
+
+/* convert DER generalized time to ascii time string, only include day,
+ not time */
+char *
+DER_GeneralizedDayToAscii(SECItem *gentime)
+{
+ return (DecodeGeneralizedTime2FormattedAscii (gentime, "%a %b %d, %Y"));
+}
+
+/* convert DER generalized or UTC time to ascii time string, only include
+ day, not time */
+char *
+DER_TimeChoiceDayToAscii(SECItem *timechoice)
+{
+ switch (timechoice->type) {
+
+ case siUTCTime:
+ return DER_UTCDayToAscii(timechoice);
+
+ case siGeneralizedTime:
+ return DER_GeneralizedDayToAscii(timechoice);
+
+ default:
+ PORT_Assert(0);
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ return NULL;
+ }
+}
+
+char *
+CERT_UTCTime2FormattedAscii (int64 utcTime, char *format)
+{
+ PRExplodedTime printableTime;
+ char *timeString;
+
+ /* Converse time to local time and decompose it into components */
+ PR_ExplodeTime(utcTime, PR_LocalTimeParameters, &printableTime);
+
+ timeString = (char *)PORT_Alloc(256);
+
+ if ( timeString ) {
+ if ( ! PR_FormatTime( timeString, 256, format, &printableTime )) {
+ PORT_Free(timeString);
+ timeString = NULL;
+ }
+ }
+
+ return (timeString);
+}
+
+char *CERT_GenTime2FormattedAscii (int64 genTime, char *format)
+{
+ PRExplodedTime printableTime;
+ char *timeString;
+
+ /* Decompose time into components */
+ PR_ExplodeTime(genTime, PR_GMTParameters, &printableTime);
+
+ timeString = (char *)PORT_Alloc(256);
+
+ if ( timeString ) {
+ if ( ! PR_FormatTime( timeString, 256, format, &printableTime )) {
+ PORT_Free(timeString);
+ timeString = NULL;
+ PORT_SetError(SEC_ERROR_OUTPUT_LEN);
+ }
+ }
+
+ return (timeString);
+}
+
+
+/* convert DER utc time to ascii time string, The format of the time string
+ depends on the input "format"
+ */
+static char *
+DecodeUTCTime2FormattedAscii (SECItem *utcTimeDER, char *format)
+{
+ int64 utcTime;
+ int rv;
+
+ rv = DER_UTCTimeToTime(&utcTime, utcTimeDER);
+ if (rv) {
+ return(NULL);
+ }
+ return (CERT_UTCTime2FormattedAscii (utcTime, format));
+}
+
+/* convert DER utc time to ascii time string, The format of the time string
+ depends on the input "format"
+ */
+static char *
+DecodeGeneralizedTime2FormattedAscii (SECItem *generalizedTimeDER, char *format)
+{
+ PRTime generalizedTime;
+ int rv;
+
+ rv = DER_GeneralizedTimeToTime(&generalizedTime, generalizedTimeDER);
+ if (rv) {
+ return(NULL);
+ }
+ return (CERT_GeneralizedTime2FormattedAscii (generalizedTime, format));
+}
+
+/* decode a SECItem containing either a SEC_ASN1_GENERALIZED_TIME
+ or a SEC_ASN1_UTC_TIME */
+
+SECStatus DER_DecodeTimeChoice(PRTime* output, const SECItem* input)
+{
+ switch (input->type) {
+ case siGeneralizedTime:
+ return DER_GeneralizedTimeToTime(output, input);
+
+ case siUTCTime:
+ return DER_UTCTimeToTime(output, input);
+
+ default:
+ PORT_SetError(SEC_ERROR_INVALID_ARGS);
+ PORT_Assert(0);
+ return SECFailure;
+ }
+}
+
+/* encode a PRTime to an ASN.1 DER SECItem containing either a
+ SEC_ASN1_GENERALIZED_TIME or a SEC_ASN1_UTC_TIME */
+
+SECStatus DER_EncodeTimeChoice(PRArenaPool* arena, SECItem* output, PRTime input)
+{
+ if (LL_CMP(input, >, January1st2050)) {
+ return DER_TimeToGeneralizedTimeArena(arena, output, input);
+ } else {
+ return DER_TimeToUTCTimeArena(arena, output, input);
+ }
+}
diff --git a/security/nss/lib/util/templates.c b/security/nss/lib/util/templates.c
new file mode 100644
index 000000000..a8dd9f726
--- /dev/null
+++ b/security/nss/lib/util/templates.c
@@ -0,0 +1,168 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Network Security Services libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * Templates that are compiled and exported from both libnss3 and libnssutil3.
+ * They have to be, because they were previously exported from libnss3, and
+ * there is no way to create data forwarder symbols on Unix.
+ *
+ * Please do not add to this file. New shared templates should be exported
+ * from libnssutil3 only.
+ *
+ */
+
+#include "utilrename.h"
+#include "secasn1.h"
+#include "secder.h"
+#include "secoid.h"
+#include "secdig.h"
+
+const SEC_ASN1Template SECOID_AlgorithmIDTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(SECAlgorithmID) },
+ { SEC_ASN1_OBJECT_ID,
+ offsetof(SECAlgorithmID,algorithm), },
+ { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY,
+ offsetof(SECAlgorithmID,parameters), },
+ { 0, }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SECOID_AlgorithmIDTemplate)
+
+const SEC_ASN1Template SEC_AnyTemplate[] = {
+ { SEC_ASN1_ANY | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_AnyTemplate)
+
+const SEC_ASN1Template SEC_BMPStringTemplate[] = {
+ { SEC_ASN1_BMP_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_BMPStringTemplate)
+
+const SEC_ASN1Template SEC_BitStringTemplate[] = {
+ { SEC_ASN1_BIT_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_BitStringTemplate)
+
+const SEC_ASN1Template SEC_BooleanTemplate[] = {
+ { SEC_ASN1_BOOLEAN, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_BooleanTemplate)
+
+const SEC_ASN1Template SEC_GeneralizedTimeTemplate[] = {
+ { SEC_ASN1_GENERALIZED_TIME | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_GeneralizedTimeTemplate)
+
+const SEC_ASN1Template SEC_IA5StringTemplate[] = {
+ { SEC_ASN1_IA5_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_IA5StringTemplate)
+
+const SEC_ASN1Template SEC_IntegerTemplate[] = {
+ { SEC_ASN1_INTEGER, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_IntegerTemplate)
+
+const SEC_ASN1Template SEC_NullTemplate[] = {
+ { SEC_ASN1_NULL, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_NullTemplate)
+
+const SEC_ASN1Template SEC_ObjectIDTemplate[] = {
+ { SEC_ASN1_OBJECT_ID, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_ObjectIDTemplate)
+
+const SEC_ASN1Template SEC_OctetStringTemplate[] = {
+ { SEC_ASN1_OCTET_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_OctetStringTemplate)
+
+const SEC_ASN1Template SEC_PointerToAnyTemplate[] = {
+ { SEC_ASN1_POINTER, 0, SEC_AnyTemplate }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PointerToAnyTemplate)
+
+const SEC_ASN1Template SEC_PointerToOctetStringTemplate[] = {
+ { SEC_ASN1_POINTER | SEC_ASN1_MAY_STREAM, 0, SEC_OctetStringTemplate }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_PointerToOctetStringTemplate)
+
+const SEC_ASN1Template SEC_SetOfAnyTemplate[] = {
+ { SEC_ASN1_SET_OF, 0, SEC_AnyTemplate }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_SetOfAnyTemplate)
+
+const SEC_ASN1Template SEC_UTCTimeTemplate[] = {
+ { SEC_ASN1_UTC_TIME | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_UTCTimeTemplate)
+
+const SEC_ASN1Template SEC_UTF8StringTemplate[] = {
+ { SEC_ASN1_UTF8_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)}
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(SEC_UTF8StringTemplate)
+
+/* XXX See comment below about SGN_DecodeDigestInfo -- keep this static! */
+/* XXX Changed from static -- need to change name? */
+const SEC_ASN1Template sgn_DigestInfoTemplate[] = {
+ { SEC_ASN1_SEQUENCE,
+ 0, NULL, sizeof(SGNDigestInfo) },
+ { SEC_ASN1_INLINE,
+ offsetof(SGNDigestInfo,digestAlgorithm),
+ SECOID_AlgorithmIDTemplate },
+ { SEC_ASN1_OCTET_STRING,
+ offsetof(SGNDigestInfo,digest) },
+ { 0 }
+};
+
+SEC_ASN1_CHOOSER_IMPLEMENT(sgn_DigestInfoTemplate)
diff --git a/security/nss/lib/util/utf8.c b/security/nss/lib/util/utf8.c
new file mode 100644
index 000000000..a50eee923
--- /dev/null
+++ b/security/nss/lib/util/utf8.c
@@ -0,0 +1,1833 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ * John Gardiner Myers <jgmyers@speakeasy.net>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifdef DEBUG
+static const char CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$";
+#endif /* DEBUG */
+
+#include "seccomon.h"
+#include "secport.h"
+
+#ifdef TEST_UTF8
+#include <assert.h>
+#undef PORT_Assert
+#define PORT_Assert assert
+#endif
+
+/*
+ * From RFC 2044:
+ *
+ * UCS-4 range (hex.) UTF-8 octet sequence (binary)
+ * 0000 0000-0000 007F 0xxxxxxx
+ * 0000 0080-0000 07FF 110xxxxx 10xxxxxx
+ * 0000 0800-0000 FFFF 1110xxxx 10xxxxxx 10xxxxxx
+ * 0001 0000-001F FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
+ * 0020 0000-03FF FFFF 111110xx 10xxxxxx 10xxxxxx 10xxxxxx 10xxxxxx
+ * 0400 0000-7FFF FFFF 1111110x 10xxxxxx ... 10xxxxxx
+ */
+
+/*
+ * From http://www.imc.org/draft-hoffman-utf16
+ *
+ * For U on [0x00010000,0x0010FFFF]: Let U' = U - 0x00010000
+ *
+ * U' = yyyyyyyyyyxxxxxxxxxx
+ * W1 = 110110yyyyyyyyyy
+ * W2 = 110111xxxxxxxxxx
+ */
+
+/*
+ * This code is assuming NETWORK BYTE ORDER for the 16- and 32-bit
+ * character values. If you wish to use this code for working with
+ * host byte order values, define the following:
+ *
+ * #if IS_BIG_ENDIAN
+ * #define L_0 0
+ * #define L_1 1
+ * #define L_2 2
+ * #define L_3 3
+ * #define H_0 0
+ * #define H_1 1
+ * #else / * not everyone has elif * /
+ * #if IS_LITTLE_ENDIAN
+ * #define L_0 3
+ * #define L_1 2
+ * #define L_2 1
+ * #define L_3 0
+ * #define H_0 1
+ * #define H_1 0
+ * #else
+ * #error "PDP and NUXI support deferred"
+ * #endif / * IS_LITTLE_ENDIAN * /
+ * #endif / * IS_BIG_ENDIAN * /
+ */
+
+#define L_0 0
+#define L_1 1
+#define L_2 2
+#define L_3 3
+#define H_0 0
+#define H_1 1
+
+#define BAD_UTF8 ((PRUint32)-1)
+
+/*
+ * Parse a single UTF-8 character per the spec. in section 3.9 (D36)
+ * of Unicode 4.0.0.
+ *
+ * Parameters:
+ * index - Points to the byte offset in inBuf of character to read. On success,
+ * updated to the offset of the following character.
+ * inBuf - Input buffer, UTF-8 encoded
+ * inbufLen - Length of input buffer, in bytes.
+ *
+ * Returns:
+ * Success - The UCS4 encoded character
+ * Failure - BAD_UTF8
+ */
+static PRUint32
+sec_port_read_utf8(unsigned int *index, unsigned char *inBuf, unsigned int inBufLen)
+{
+ PRUint32 result;
+ unsigned int i = *index;
+ int bytes_left;
+ PRUint32 min_value;
+
+ PORT_Assert(i < inBufLen);
+
+ if ( (inBuf[i] & 0x80) == 0x00 ) {
+ result = inBuf[i++];
+ bytes_left = 0;
+ min_value = 0;
+ } else if ( (inBuf[i] & 0xE0) == 0xC0 ) {
+ result = inBuf[i++] & 0x1F;
+ bytes_left = 1;
+ min_value = 0x80;
+ } else if ( (inBuf[i] & 0xF0) == 0xE0) {
+ result = inBuf[i++] & 0x0F;
+ bytes_left = 2;
+ min_value = 0x800;
+ } else if ( (inBuf[i] & 0xF8) == 0xF0) {
+ result = inBuf[i++] & 0x07;
+ bytes_left = 3;
+ min_value = 0x10000;
+ } else {
+ return BAD_UTF8;
+ }
+
+ while (bytes_left--) {
+ if (i >= inBufLen || (inBuf[i] & 0xC0) != 0x80) return BAD_UTF8;
+ result = (result << 6) | (inBuf[i++] & 0x3F);
+ }
+
+ /* Check for overlong sequences, surrogates, and outside unicode range */
+ if (result < min_value || (result & 0xFFFFF800) == 0xD800 || result > 0x10FFFF) {
+ return BAD_UTF8;
+ }
+
+ *index = i;
+ return result;
+}
+
+PRBool
+sec_port_ucs4_utf8_conversion_function
+(
+ PRBool toUnicode,
+ unsigned char *inBuf,
+ unsigned int inBufLen,
+ unsigned char *outBuf,
+ unsigned int maxOutBufLen,
+ unsigned int *outBufLen
+)
+{
+ PORT_Assert((unsigned int *)NULL != outBufLen);
+
+ if( toUnicode ) {
+ unsigned int i, len = 0;
+
+ for( i = 0; i < inBufLen; ) {
+ if( (inBuf[i] & 0x80) == 0x00 ) i += 1;
+ else if( (inBuf[i] & 0xE0) == 0xC0 ) i += 2;
+ else if( (inBuf[i] & 0xF0) == 0xE0 ) i += 3;
+ else if( (inBuf[i] & 0xF8) == 0xF0 ) i += 4;
+ else return PR_FALSE;
+
+ len += 4;
+ }
+
+ if( len > maxOutBufLen ) {
+ *outBufLen = len;
+ return PR_FALSE;
+ }
+
+ len = 0;
+
+ for( i = 0; i < inBufLen; ) {
+ PRUint32 ucs4 = sec_port_read_utf8(&i, inBuf, inBufLen);
+
+ if (ucs4 == BAD_UTF8) return PR_FALSE;
+
+ outBuf[len+L_0] = 0x00;
+ outBuf[len+L_1] = (unsigned char)(ucs4 >> 16);
+ outBuf[len+L_2] = (unsigned char)(ucs4 >> 8);
+ outBuf[len+L_3] = (unsigned char)ucs4;
+
+ len += 4;
+ }
+
+ *outBufLen = len;
+ return PR_TRUE;
+ } else {
+ unsigned int i, len = 0;
+ PORT_Assert((inBufLen % 4) == 0);
+ if ((inBufLen % 4) != 0) {
+ *outBufLen = 0;
+ return PR_FALSE;
+ }
+
+ for( i = 0; i < inBufLen; i += 4 ) {
+ if( (inBuf[i+L_0] > 0x00) || (inBuf[i+L_1] > 0x10) ) {
+ *outBufLen = 0;
+ return PR_FALSE;
+ } else if( inBuf[i+L_1] >= 0x01 ) len += 4;
+ else if( inBuf[i+L_2] >= 0x08 ) len += 3;
+ else if( (inBuf[i+L_2] > 0x00) || (inBuf[i+L_3] >= 0x80) ) len += 2;
+ else len += 1;
+ }
+
+ if( len > maxOutBufLen ) {
+ *outBufLen = len;
+ return PR_FALSE;
+ }
+
+ len = 0;
+
+ for( i = 0; i < inBufLen; i += 4 ) {
+ if( inBuf[i+L_1] >= 0x01 ) {
+ /* 0001 0000-001F FFFF -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+ /* 00000000 000abcde fghijklm nopqrstu ->
+ 11110abc 10defghi 10jklmno 10pqrstu */
+
+ outBuf[len+0] = 0xF0 | ((inBuf[i+L_1] & 0x1C) >> 2);
+ outBuf[len+1] = 0x80 | ((inBuf[i+L_1] & 0x03) << 4)
+ | ((inBuf[i+L_2] & 0xF0) >> 4);
+ outBuf[len+2] = 0x80 | ((inBuf[i+L_2] & 0x0F) << 2)
+ | ((inBuf[i+L_3] & 0xC0) >> 6);
+ outBuf[len+3] = 0x80 | ((inBuf[i+L_3] & 0x3F) >> 0);
+
+ len += 4;
+ } else if( inBuf[i+L_2] >= 0x08 ) {
+ /* 0000 0800-0000 FFFF -> 1110xxxx 10xxxxxx 10xxxxxx */
+ /* 00000000 00000000 abcdefgh ijklmnop ->
+ 1110abcd 10efghij 10klmnop */
+
+ outBuf[len+0] = 0xE0 | ((inBuf[i+L_2] & 0xF0) >> 4);
+ outBuf[len+1] = 0x80 | ((inBuf[i+L_2] & 0x0F) << 2)
+ | ((inBuf[i+L_3] & 0xC0) >> 6);
+ outBuf[len+2] = 0x80 | ((inBuf[i+L_3] & 0x3F) >> 0);
+
+ len += 3;
+ } else if( (inBuf[i+L_2] > 0x00) || (inBuf[i+L_3] >= 0x80) ) {
+ /* 0000 0080-0000 07FF -> 110xxxxx 10xxxxxx */
+ /* 00000000 00000000 00000abc defghijk ->
+ 110abcde 10fghijk */
+
+ outBuf[len+0] = 0xC0 | ((inBuf[i+L_2] & 0x07) << 2)
+ | ((inBuf[i+L_3] & 0xC0) >> 6);
+ outBuf[len+1] = 0x80 | ((inBuf[i+L_3] & 0x3F) >> 0);
+
+ len += 2;
+ } else {
+ /* 0000 0000-0000 007F -> 0xxxxxx */
+ /* 00000000 00000000 00000000 0abcdefg ->
+ 0abcdefg */
+
+ outBuf[len+0] = (inBuf[i+L_3] & 0x7F);
+
+ len += 1;
+ }
+ }
+
+ *outBufLen = len;
+ return PR_TRUE;
+ }
+}
+
+PRBool
+sec_port_ucs2_utf8_conversion_function
+(
+ PRBool toUnicode,
+ unsigned char *inBuf,
+ unsigned int inBufLen,
+ unsigned char *outBuf,
+ unsigned int maxOutBufLen,
+ unsigned int *outBufLen
+)
+{
+ PORT_Assert((unsigned int *)NULL != outBufLen);
+
+ if( toUnicode ) {
+ unsigned int i, len = 0;
+
+ for( i = 0; i < inBufLen; ) {
+ if( (inBuf[i] & 0x80) == 0x00 ) {
+ i += 1;
+ len += 2;
+ } else if( (inBuf[i] & 0xE0) == 0xC0 ) {
+ i += 2;
+ len += 2;
+ } else if( (inBuf[i] & 0xF0) == 0xE0 ) {
+ i += 3;
+ len += 2;
+ } else if( (inBuf[i] & 0xF8) == 0xF0 ) {
+ i += 4;
+ len += 4;
+ } else return PR_FALSE;
+ }
+
+ if( len > maxOutBufLen ) {
+ *outBufLen = len;
+ return PR_FALSE;
+ }
+
+ len = 0;
+
+ for( i = 0; i < inBufLen; ) {
+ PRUint32 ucs4 = sec_port_read_utf8(&i, inBuf, inBufLen);
+
+ if (ucs4 == BAD_UTF8) return PR_FALSE;
+
+ if( ucs4 < 0x10000) {
+ outBuf[len+H_0] = (unsigned char)(ucs4 >> 8);
+ outBuf[len+H_1] = (unsigned char)ucs4;
+ len += 2;
+ } else {
+ ucs4 -= 0x10000;
+ outBuf[len+0+H_0] = (unsigned char)(0xD8 | ((ucs4 >> 18) & 0x3));
+ outBuf[len+0+H_1] = (unsigned char)(ucs4 >> 10);
+ outBuf[len+2+H_0] = (unsigned char)(0xDC | ((ucs4 >> 8) & 0x3));
+ outBuf[len+2+H_1] = (unsigned char)ucs4;
+ len += 4;
+ }
+ }
+
+ *outBufLen = len;
+ return PR_TRUE;
+ } else {
+ unsigned int i, len = 0;
+ PORT_Assert((inBufLen % 2) == 0);
+ if ((inBufLen % 2) != 0) {
+ *outBufLen = 0;
+ return PR_FALSE;
+ }
+
+ for( i = 0; i < inBufLen; i += 2 ) {
+ if( (inBuf[i+H_0] == 0x00) && ((inBuf[i+H_0] & 0x80) == 0x00) ) len += 1;
+ else if( inBuf[i+H_0] < 0x08 ) len += 2;
+ else if( ((inBuf[i+0+H_0] & 0xDC) == 0xD8) ) {
+ if( ((inBuf[i+2+H_0] & 0xDC) == 0xDC) && ((inBufLen - i) > 2) ) {
+ i += 2;
+ len += 4;
+ } else {
+ return PR_FALSE;
+ }
+ }
+ else len += 3;
+ }
+
+ if( len > maxOutBufLen ) {
+ *outBufLen = len;
+ return PR_FALSE;
+ }
+
+ len = 0;
+
+ for( i = 0; i < inBufLen; i += 2 ) {
+ if( (inBuf[i+H_0] == 0x00) && ((inBuf[i+H_1] & 0x80) == 0x00) ) {
+ /* 0000-007F -> 0xxxxxx */
+ /* 00000000 0abcdefg -> 0abcdefg */
+
+ outBuf[len] = inBuf[i+H_1] & 0x7F;
+
+ len += 1;
+ } else if( inBuf[i+H_0] < 0x08 ) {
+ /* 0080-07FF -> 110xxxxx 10xxxxxx */
+ /* 00000abc defghijk -> 110abcde 10fghijk */
+
+ outBuf[len+0] = 0xC0 | ((inBuf[i+H_0] & 0x07) << 2)
+ | ((inBuf[i+H_1] & 0xC0) >> 6);
+ outBuf[len+1] = 0x80 | ((inBuf[i+H_1] & 0x3F) >> 0);
+
+ len += 2;
+ } else if( (inBuf[i+H_0] & 0xDC) == 0xD8 ) {
+ int abcde, BCDE;
+
+ PORT_Assert(((inBuf[i+2+H_0] & 0xDC) == 0xDC) && ((inBufLen - i) > 2));
+
+ /* D800-DBFF DC00-DFFF -> 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */
+ /* 110110BC DEfghijk 110111lm nopqrstu ->
+ { Let abcde = BCDE + 1 }
+ 11110abc 10defghi 10jklmno 10pqrstu */
+
+ BCDE = ((inBuf[i+H_0] & 0x03) << 2) | ((inBuf[i+H_1] & 0xC0) >> 6);
+ abcde = BCDE + 1;
+
+ outBuf[len+0] = 0xF0 | ((abcde & 0x1C) >> 2);
+ outBuf[len+1] = 0x80 | ((abcde & 0x03) << 4)
+ | ((inBuf[i+0+H_1] & 0x3C) >> 2);
+ outBuf[len+2] = 0x80 | ((inBuf[i+0+H_1] & 0x03) << 4)
+ | ((inBuf[i+2+H_0] & 0x03) << 2)
+ | ((inBuf[i+2+H_1] & 0xC0) >> 6);
+ outBuf[len+3] = 0x80 | ((inBuf[i+2+H_1] & 0x3F) >> 0);
+
+ i += 2;
+ len += 4;
+ } else {
+ /* 0800-FFFF -> 1110xxxx 10xxxxxx 10xxxxxx */
+ /* abcdefgh ijklmnop -> 1110abcd 10efghij 10klmnop */
+
+ outBuf[len+0] = 0xE0 | ((inBuf[i+H_0] & 0xF0) >> 4);
+ outBuf[len+1] = 0x80 | ((inBuf[i+H_0] & 0x0F) << 2)
+ | ((inBuf[i+H_1] & 0xC0) >> 6);
+ outBuf[len+2] = 0x80 | ((inBuf[i+H_1] & 0x3F) >> 0);
+
+ len += 3;
+ }
+ }
+
+ *outBufLen = len;
+ return PR_TRUE;
+ }
+}
+
+PRBool
+sec_port_iso88591_utf8_conversion_function
+(
+ const unsigned char *inBuf,
+ unsigned int inBufLen,
+ unsigned char *outBuf,
+ unsigned int maxOutBufLen,
+ unsigned int *outBufLen
+)
+{
+ unsigned int i, len = 0;
+
+ PORT_Assert((unsigned int *)NULL != outBufLen);
+
+ for( i = 0; i < inBufLen; i++) {
+ if( (inBuf[i] & 0x80) == 0x00 ) len += 1;
+ else len += 2;
+ }
+
+ if( len > maxOutBufLen ) {
+ *outBufLen = len;
+ return PR_FALSE;
+ }
+
+ len = 0;
+
+ for( i = 0; i < inBufLen; i++) {
+ if( (inBuf[i] & 0x80) == 0x00 ) {
+ /* 00-7F -> 0xxxxxxx */
+ /* 0abcdefg -> 0abcdefg */
+
+ outBuf[len] = inBuf[i];
+ len += 1;
+ } else {
+ /* 80-FF <- 110xxxxx 10xxxxxx */
+ /* 00000000 abcdefgh -> 110000ab 10cdefgh */
+
+ outBuf[len+0] = 0xC0 | ((inBuf[i] & 0xC0) >> 6);
+ outBuf[len+1] = 0x80 | ((inBuf[i] & 0x3F) >> 0);
+
+ len += 2;
+ }
+ }
+
+ *outBufLen = len;
+ return PR_TRUE;
+}
+
+#ifdef TEST_UTF8
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netinet/in.h> /* for htonl and htons */
+
+/*
+ * UCS-4 vectors
+ */
+
+struct ucs4 {
+ PRUint32 c;
+ char *utf8;
+};
+
+/*
+ * UCS-2 vectors
+ */
+
+struct ucs2 {
+ PRUint16 c;
+ char *utf8;
+};
+
+/*
+ * UTF-16 vectors
+ */
+
+struct utf16 {
+ PRUint32 c;
+ PRUint16 w[2];
+};
+
+
+/*
+ * UCS-4 vectors
+ */
+
+struct ucs4 ucs4[] = {
+ { 0x00000001, "\x01" },
+ { 0x00000002, "\x02" },
+ { 0x00000003, "\x03" },
+ { 0x00000004, "\x04" },
+ { 0x00000007, "\x07" },
+ { 0x00000008, "\x08" },
+ { 0x0000000F, "\x0F" },
+ { 0x00000010, "\x10" },
+ { 0x0000001F, "\x1F" },
+ { 0x00000020, "\x20" },
+ { 0x0000003F, "\x3F" },
+ { 0x00000040, "\x40" },
+ { 0x0000007F, "\x7F" },
+
+ { 0x00000080, "\xC2\x80" },
+ { 0x00000081, "\xC2\x81" },
+ { 0x00000082, "\xC2\x82" },
+ { 0x00000084, "\xC2\x84" },
+ { 0x00000088, "\xC2\x88" },
+ { 0x00000090, "\xC2\x90" },
+ { 0x000000A0, "\xC2\xA0" },
+ { 0x000000C0, "\xC3\x80" },
+ { 0x000000FF, "\xC3\xBF" },
+ { 0x00000100, "\xC4\x80" },
+ { 0x00000101, "\xC4\x81" },
+ { 0x00000102, "\xC4\x82" },
+ { 0x00000104, "\xC4\x84" },
+ { 0x00000108, "\xC4\x88" },
+ { 0x00000110, "\xC4\x90" },
+ { 0x00000120, "\xC4\xA0" },
+ { 0x00000140, "\xC5\x80" },
+ { 0x00000180, "\xC6\x80" },
+ { 0x000001FF, "\xC7\xBF" },
+ { 0x00000200, "\xC8\x80" },
+ { 0x00000201, "\xC8\x81" },
+ { 0x00000202, "\xC8\x82" },
+ { 0x00000204, "\xC8\x84" },
+ { 0x00000208, "\xC8\x88" },
+ { 0x00000210, "\xC8\x90" },
+ { 0x00000220, "\xC8\xA0" },
+ { 0x00000240, "\xC9\x80" },
+ { 0x00000280, "\xCA\x80" },
+ { 0x00000300, "\xCC\x80" },
+ { 0x000003FF, "\xCF\xBF" },
+ { 0x00000400, "\xD0\x80" },
+ { 0x00000401, "\xD0\x81" },
+ { 0x00000402, "\xD0\x82" },
+ { 0x00000404, "\xD0\x84" },
+ { 0x00000408, "\xD0\x88" },
+ { 0x00000410, "\xD0\x90" },
+ { 0x00000420, "\xD0\xA0" },
+ { 0x00000440, "\xD1\x80" },
+ { 0x00000480, "\xD2\x80" },
+ { 0x00000500, "\xD4\x80" },
+ { 0x00000600, "\xD8\x80" },
+ { 0x000007FF, "\xDF\xBF" },
+
+ { 0x00000800, "\xE0\xA0\x80" },
+ { 0x00000801, "\xE0\xA0\x81" },
+ { 0x00000802, "\xE0\xA0\x82" },
+ { 0x00000804, "\xE0\xA0\x84" },
+ { 0x00000808, "\xE0\xA0\x88" },
+ { 0x00000810, "\xE0\xA0\x90" },
+ { 0x00000820, "\xE0\xA0\xA0" },
+ { 0x00000840, "\xE0\xA1\x80" },
+ { 0x00000880, "\xE0\xA2\x80" },
+ { 0x00000900, "\xE0\xA4\x80" },
+ { 0x00000A00, "\xE0\xA8\x80" },
+ { 0x00000C00, "\xE0\xB0\x80" },
+ { 0x00000FFF, "\xE0\xBF\xBF" },
+ { 0x00001000, "\xE1\x80\x80" },
+ { 0x00001001, "\xE1\x80\x81" },
+ { 0x00001002, "\xE1\x80\x82" },
+ { 0x00001004, "\xE1\x80\x84" },
+ { 0x00001008, "\xE1\x80\x88" },
+ { 0x00001010, "\xE1\x80\x90" },
+ { 0x00001020, "\xE1\x80\xA0" },
+ { 0x00001040, "\xE1\x81\x80" },
+ { 0x00001080, "\xE1\x82\x80" },
+ { 0x00001100, "\xE1\x84\x80" },
+ { 0x00001200, "\xE1\x88\x80" },
+ { 0x00001400, "\xE1\x90\x80" },
+ { 0x00001800, "\xE1\xA0\x80" },
+ { 0x00001FFF, "\xE1\xBF\xBF" },
+ { 0x00002000, "\xE2\x80\x80" },
+ { 0x00002001, "\xE2\x80\x81" },
+ { 0x00002002, "\xE2\x80\x82" },
+ { 0x00002004, "\xE2\x80\x84" },
+ { 0x00002008, "\xE2\x80\x88" },
+ { 0x00002010, "\xE2\x80\x90" },
+ { 0x00002020, "\xE2\x80\xA0" },
+ { 0x00002040, "\xE2\x81\x80" },
+ { 0x00002080, "\xE2\x82\x80" },
+ { 0x00002100, "\xE2\x84\x80" },
+ { 0x00002200, "\xE2\x88\x80" },
+ { 0x00002400, "\xE2\x90\x80" },
+ { 0x00002800, "\xE2\xA0\x80" },
+ { 0x00003000, "\xE3\x80\x80" },
+ { 0x00003FFF, "\xE3\xBF\xBF" },
+ { 0x00004000, "\xE4\x80\x80" },
+ { 0x00004001, "\xE4\x80\x81" },
+ { 0x00004002, "\xE4\x80\x82" },
+ { 0x00004004, "\xE4\x80\x84" },
+ { 0x00004008, "\xE4\x80\x88" },
+ { 0x00004010, "\xE4\x80\x90" },
+ { 0x00004020, "\xE4\x80\xA0" },
+ { 0x00004040, "\xE4\x81\x80" },
+ { 0x00004080, "\xE4\x82\x80" },
+ { 0x00004100, "\xE4\x84\x80" },
+ { 0x00004200, "\xE4\x88\x80" },
+ { 0x00004400, "\xE4\x90\x80" },
+ { 0x00004800, "\xE4\xA0\x80" },
+ { 0x00005000, "\xE5\x80\x80" },
+ { 0x00006000, "\xE6\x80\x80" },
+ { 0x00007FFF, "\xE7\xBF\xBF" },
+ { 0x00008000, "\xE8\x80\x80" },
+ { 0x00008001, "\xE8\x80\x81" },
+ { 0x00008002, "\xE8\x80\x82" },
+ { 0x00008004, "\xE8\x80\x84" },
+ { 0x00008008, "\xE8\x80\x88" },
+ { 0x00008010, "\xE8\x80\x90" },
+ { 0x00008020, "\xE8\x80\xA0" },
+ { 0x00008040, "\xE8\x81\x80" },
+ { 0x00008080, "\xE8\x82\x80" },
+ { 0x00008100, "\xE8\x84\x80" },
+ { 0x00008200, "\xE8\x88\x80" },
+ { 0x00008400, "\xE8\x90\x80" },
+ { 0x00008800, "\xE8\xA0\x80" },
+ { 0x00009000, "\xE9\x80\x80" },
+ { 0x0000A000, "\xEA\x80\x80" },
+ { 0x0000C000, "\xEC\x80\x80" },
+ { 0x0000FFFF, "\xEF\xBF\xBF" },
+
+ { 0x00010000, "\xF0\x90\x80\x80" },
+ { 0x00010001, "\xF0\x90\x80\x81" },
+ { 0x00010002, "\xF0\x90\x80\x82" },
+ { 0x00010004, "\xF0\x90\x80\x84" },
+ { 0x00010008, "\xF0\x90\x80\x88" },
+ { 0x00010010, "\xF0\x90\x80\x90" },
+ { 0x00010020, "\xF0\x90\x80\xA0" },
+ { 0x00010040, "\xF0\x90\x81\x80" },
+ { 0x00010080, "\xF0\x90\x82\x80" },
+ { 0x00010100, "\xF0\x90\x84\x80" },
+ { 0x00010200, "\xF0\x90\x88\x80" },
+ { 0x00010400, "\xF0\x90\x90\x80" },
+ { 0x00010800, "\xF0\x90\xA0\x80" },
+ { 0x00011000, "\xF0\x91\x80\x80" },
+ { 0x00012000, "\xF0\x92\x80\x80" },
+ { 0x00014000, "\xF0\x94\x80\x80" },
+ { 0x00018000, "\xF0\x98\x80\x80" },
+ { 0x0001FFFF, "\xF0\x9F\xBF\xBF" },
+ { 0x00020000, "\xF0\xA0\x80\x80" },
+ { 0x00020001, "\xF0\xA0\x80\x81" },
+ { 0x00020002, "\xF0\xA0\x80\x82" },
+ { 0x00020004, "\xF0\xA0\x80\x84" },
+ { 0x00020008, "\xF0\xA0\x80\x88" },
+ { 0x00020010, "\xF0\xA0\x80\x90" },
+ { 0x00020020, "\xF0\xA0\x80\xA0" },
+ { 0x00020040, "\xF0\xA0\x81\x80" },
+ { 0x00020080, "\xF0\xA0\x82\x80" },
+ { 0x00020100, "\xF0\xA0\x84\x80" },
+ { 0x00020200, "\xF0\xA0\x88\x80" },
+ { 0x00020400, "\xF0\xA0\x90\x80" },
+ { 0x00020800, "\xF0\xA0\xA0\x80" },
+ { 0x00021000, "\xF0\xA1\x80\x80" },
+ { 0x00022000, "\xF0\xA2\x80\x80" },
+ { 0x00024000, "\xF0\xA4\x80\x80" },
+ { 0x00028000, "\xF0\xA8\x80\x80" },
+ { 0x00030000, "\xF0\xB0\x80\x80" },
+ { 0x0003FFFF, "\xF0\xBF\xBF\xBF" },
+ { 0x00040000, "\xF1\x80\x80\x80" },
+ { 0x00040001, "\xF1\x80\x80\x81" },
+ { 0x00040002, "\xF1\x80\x80\x82" },
+ { 0x00040004, "\xF1\x80\x80\x84" },
+ { 0x00040008, "\xF1\x80\x80\x88" },
+ { 0x00040010, "\xF1\x80\x80\x90" },
+ { 0x00040020, "\xF1\x80\x80\xA0" },
+ { 0x00040040, "\xF1\x80\x81\x80" },
+ { 0x00040080, "\xF1\x80\x82\x80" },
+ { 0x00040100, "\xF1\x80\x84\x80" },
+ { 0x00040200, "\xF1\x80\x88\x80" },
+ { 0x00040400, "\xF1\x80\x90\x80" },
+ { 0x00040800, "\xF1\x80\xA0\x80" },
+ { 0x00041000, "\xF1\x81\x80\x80" },
+ { 0x00042000, "\xF1\x82\x80\x80" },
+ { 0x00044000, "\xF1\x84\x80\x80" },
+ { 0x00048000, "\xF1\x88\x80\x80" },
+ { 0x00050000, "\xF1\x90\x80\x80" },
+ { 0x00060000, "\xF1\xA0\x80\x80" },
+ { 0x0007FFFF, "\xF1\xBF\xBF\xBF" },
+ { 0x00080000, "\xF2\x80\x80\x80" },
+ { 0x00080001, "\xF2\x80\x80\x81" },
+ { 0x00080002, "\xF2\x80\x80\x82" },
+ { 0x00080004, "\xF2\x80\x80\x84" },
+ { 0x00080008, "\xF2\x80\x80\x88" },
+ { 0x00080010, "\xF2\x80\x80\x90" },
+ { 0x00080020, "\xF2\x80\x80\xA0" },
+ { 0x00080040, "\xF2\x80\x81\x80" },
+ { 0x00080080, "\xF2\x80\x82\x80" },
+ { 0x00080100, "\xF2\x80\x84\x80" },
+ { 0x00080200, "\xF2\x80\x88\x80" },
+ { 0x00080400, "\xF2\x80\x90\x80" },
+ { 0x00080800, "\xF2\x80\xA0\x80" },
+ { 0x00081000, "\xF2\x81\x80\x80" },
+ { 0x00082000, "\xF2\x82\x80\x80" },
+ { 0x00084000, "\xF2\x84\x80\x80" },
+ { 0x00088000, "\xF2\x88\x80\x80" },
+ { 0x00090000, "\xF2\x90\x80\x80" },
+ { 0x000A0000, "\xF2\xA0\x80\x80" },
+ { 0x000C0000, "\xF3\x80\x80\x80" },
+ { 0x000FFFFF, "\xF3\xBF\xBF\xBF" },
+ { 0x00100000, "\xF4\x80\x80\x80" },
+ { 0x00100001, "\xF4\x80\x80\x81" },
+ { 0x00100002, "\xF4\x80\x80\x82" },
+ { 0x00100004, "\xF4\x80\x80\x84" },
+ { 0x00100008, "\xF4\x80\x80\x88" },
+ { 0x00100010, "\xF4\x80\x80\x90" },
+ { 0x00100020, "\xF4\x80\x80\xA0" },
+ { 0x00100040, "\xF4\x80\x81\x80" },
+ { 0x00100080, "\xF4\x80\x82\x80" },
+ { 0x00100100, "\xF4\x80\x84\x80" },
+ { 0x00100200, "\xF4\x80\x88\x80" },
+ { 0x00100400, "\xF4\x80\x90\x80" },
+ { 0x00100800, "\xF4\x80\xA0\x80" },
+ { 0x00101000, "\xF4\x81\x80\x80" },
+ { 0x00102000, "\xF4\x82\x80\x80" },
+ { 0x00104000, "\xF4\x84\x80\x80" },
+ { 0x00108000, "\xF4\x88\x80\x80" },
+ { 0x0010FFFF, "\xF4\x8F\xBF\xBF" },
+};
+
+/*
+ * UCS-2 vectors
+ */
+
+struct ucs2 ucs2[] = {
+ { 0x0001, "\x01" },
+ { 0x0002, "\x02" },
+ { 0x0003, "\x03" },
+ { 0x0004, "\x04" },
+ { 0x0007, "\x07" },
+ { 0x0008, "\x08" },
+ { 0x000F, "\x0F" },
+ { 0x0010, "\x10" },
+ { 0x001F, "\x1F" },
+ { 0x0020, "\x20" },
+ { 0x003F, "\x3F" },
+ { 0x0040, "\x40" },
+ { 0x007F, "\x7F" },
+
+ { 0x0080, "\xC2\x80" },
+ { 0x0081, "\xC2\x81" },
+ { 0x0082, "\xC2\x82" },
+ { 0x0084, "\xC2\x84" },
+ { 0x0088, "\xC2\x88" },
+ { 0x0090, "\xC2\x90" },
+ { 0x00A0, "\xC2\xA0" },
+ { 0x00C0, "\xC3\x80" },
+ { 0x00FF, "\xC3\xBF" },
+ { 0x0100, "\xC4\x80" },
+ { 0x0101, "\xC4\x81" },
+ { 0x0102, "\xC4\x82" },
+ { 0x0104, "\xC4\x84" },
+ { 0x0108, "\xC4\x88" },
+ { 0x0110, "\xC4\x90" },
+ { 0x0120, "\xC4\xA0" },
+ { 0x0140, "\xC5\x80" },
+ { 0x0180, "\xC6\x80" },
+ { 0x01FF, "\xC7\xBF" },
+ { 0x0200, "\xC8\x80" },
+ { 0x0201, "\xC8\x81" },
+ { 0x0202, "\xC8\x82" },
+ { 0x0204, "\xC8\x84" },
+ { 0x0208, "\xC8\x88" },
+ { 0x0210, "\xC8\x90" },
+ { 0x0220, "\xC8\xA0" },
+ { 0x0240, "\xC9\x80" },
+ { 0x0280, "\xCA\x80" },
+ { 0x0300, "\xCC\x80" },
+ { 0x03FF, "\xCF\xBF" },
+ { 0x0400, "\xD0\x80" },
+ { 0x0401, "\xD0\x81" },
+ { 0x0402, "\xD0\x82" },
+ { 0x0404, "\xD0\x84" },
+ { 0x0408, "\xD0\x88" },
+ { 0x0410, "\xD0\x90" },
+ { 0x0420, "\xD0\xA0" },
+ { 0x0440, "\xD1\x80" },
+ { 0x0480, "\xD2\x80" },
+ { 0x0500, "\xD4\x80" },
+ { 0x0600, "\xD8\x80" },
+ { 0x07FF, "\xDF\xBF" },
+
+ { 0x0800, "\xE0\xA0\x80" },
+ { 0x0801, "\xE0\xA0\x81" },
+ { 0x0802, "\xE0\xA0\x82" },
+ { 0x0804, "\xE0\xA0\x84" },
+ { 0x0808, "\xE0\xA0\x88" },
+ { 0x0810, "\xE0\xA0\x90" },
+ { 0x0820, "\xE0\xA0\xA0" },
+ { 0x0840, "\xE0\xA1\x80" },
+ { 0x0880, "\xE0\xA2\x80" },
+ { 0x0900, "\xE0\xA4\x80" },
+ { 0x0A00, "\xE0\xA8\x80" },
+ { 0x0C00, "\xE0\xB0\x80" },
+ { 0x0FFF, "\xE0\xBF\xBF" },
+ { 0x1000, "\xE1\x80\x80" },
+ { 0x1001, "\xE1\x80\x81" },
+ { 0x1002, "\xE1\x80\x82" },
+ { 0x1004, "\xE1\x80\x84" },
+ { 0x1008, "\xE1\x80\x88" },
+ { 0x1010, "\xE1\x80\x90" },
+ { 0x1020, "\xE1\x80\xA0" },
+ { 0x1040, "\xE1\x81\x80" },
+ { 0x1080, "\xE1\x82\x80" },
+ { 0x1100, "\xE1\x84\x80" },
+ { 0x1200, "\xE1\x88\x80" },
+ { 0x1400, "\xE1\x90\x80" },
+ { 0x1800, "\xE1\xA0\x80" },
+ { 0x1FFF, "\xE1\xBF\xBF" },
+ { 0x2000, "\xE2\x80\x80" },
+ { 0x2001, "\xE2\x80\x81" },
+ { 0x2002, "\xE2\x80\x82" },
+ { 0x2004, "\xE2\x80\x84" },
+ { 0x2008, "\xE2\x80\x88" },
+ { 0x2010, "\xE2\x80\x90" },
+ { 0x2020, "\xE2\x80\xA0" },
+ { 0x2040, "\xE2\x81\x80" },
+ { 0x2080, "\xE2\x82\x80" },
+ { 0x2100, "\xE2\x84\x80" },
+ { 0x2200, "\xE2\x88\x80" },
+ { 0x2400, "\xE2\x90\x80" },
+ { 0x2800, "\xE2\xA0\x80" },
+ { 0x3000, "\xE3\x80\x80" },
+ { 0x3FFF, "\xE3\xBF\xBF" },
+ { 0x4000, "\xE4\x80\x80" },
+ { 0x4001, "\xE4\x80\x81" },
+ { 0x4002, "\xE4\x80\x82" },
+ { 0x4004, "\xE4\x80\x84" },
+ { 0x4008, "\xE4\x80\x88" },
+ { 0x4010, "\xE4\x80\x90" },
+ { 0x4020, "\xE4\x80\xA0" },
+ { 0x4040, "\xE4\x81\x80" },
+ { 0x4080, "\xE4\x82\x80" },
+ { 0x4100, "\xE4\x84\x80" },
+ { 0x4200, "\xE4\x88\x80" },
+ { 0x4400, "\xE4\x90\x80" },
+ { 0x4800, "\xE4\xA0\x80" },
+ { 0x5000, "\xE5\x80\x80" },
+ { 0x6000, "\xE6\x80\x80" },
+ { 0x7FFF, "\xE7\xBF\xBF" },
+ { 0x8000, "\xE8\x80\x80" },
+ { 0x8001, "\xE8\x80\x81" },
+ { 0x8002, "\xE8\x80\x82" },
+ { 0x8004, "\xE8\x80\x84" },
+ { 0x8008, "\xE8\x80\x88" },
+ { 0x8010, "\xE8\x80\x90" },
+ { 0x8020, "\xE8\x80\xA0" },
+ { 0x8040, "\xE8\x81\x80" },
+ { 0x8080, "\xE8\x82\x80" },
+ { 0x8100, "\xE8\x84\x80" },
+ { 0x8200, "\xE8\x88\x80" },
+ { 0x8400, "\xE8\x90\x80" },
+ { 0x8800, "\xE8\xA0\x80" },
+ { 0x9000, "\xE9\x80\x80" },
+ { 0xA000, "\xEA\x80\x80" },
+ { 0xC000, "\xEC\x80\x80" },
+ { 0xFFFF, "\xEF\xBF\xBF" }
+
+};
+
+/*
+ * UTF-16 vectors
+ */
+
+struct utf16 utf16[] = {
+ { 0x00010000, { 0xD800, 0xDC00 } },
+ { 0x00010001, { 0xD800, 0xDC01 } },
+ { 0x00010002, { 0xD800, 0xDC02 } },
+ { 0x00010003, { 0xD800, 0xDC03 } },
+ { 0x00010004, { 0xD800, 0xDC04 } },
+ { 0x00010007, { 0xD800, 0xDC07 } },
+ { 0x00010008, { 0xD800, 0xDC08 } },
+ { 0x0001000F, { 0xD800, 0xDC0F } },
+ { 0x00010010, { 0xD800, 0xDC10 } },
+ { 0x0001001F, { 0xD800, 0xDC1F } },
+ { 0x00010020, { 0xD800, 0xDC20 } },
+ { 0x0001003F, { 0xD800, 0xDC3F } },
+ { 0x00010040, { 0xD800, 0xDC40 } },
+ { 0x0001007F, { 0xD800, 0xDC7F } },
+ { 0x00010080, { 0xD800, 0xDC80 } },
+ { 0x00010081, { 0xD800, 0xDC81 } },
+ { 0x00010082, { 0xD800, 0xDC82 } },
+ { 0x00010084, { 0xD800, 0xDC84 } },
+ { 0x00010088, { 0xD800, 0xDC88 } },
+ { 0x00010090, { 0xD800, 0xDC90 } },
+ { 0x000100A0, { 0xD800, 0xDCA0 } },
+ { 0x000100C0, { 0xD800, 0xDCC0 } },
+ { 0x000100FF, { 0xD800, 0xDCFF } },
+ { 0x00010100, { 0xD800, 0xDD00 } },
+ { 0x00010101, { 0xD800, 0xDD01 } },
+ { 0x00010102, { 0xD800, 0xDD02 } },
+ { 0x00010104, { 0xD800, 0xDD04 } },
+ { 0x00010108, { 0xD800, 0xDD08 } },
+ { 0x00010110, { 0xD800, 0xDD10 } },
+ { 0x00010120, { 0xD800, 0xDD20 } },
+ { 0x00010140, { 0xD800, 0xDD40 } },
+ { 0x00010180, { 0xD800, 0xDD80 } },
+ { 0x000101FF, { 0xD800, 0xDDFF } },
+ { 0x00010200, { 0xD800, 0xDE00 } },
+ { 0x00010201, { 0xD800, 0xDE01 } },
+ { 0x00010202, { 0xD800, 0xDE02 } },
+ { 0x00010204, { 0xD800, 0xDE04 } },
+ { 0x00010208, { 0xD800, 0xDE08 } },
+ { 0x00010210, { 0xD800, 0xDE10 } },
+ { 0x00010220, { 0xD800, 0xDE20 } },
+ { 0x00010240, { 0xD800, 0xDE40 } },
+ { 0x00010280, { 0xD800, 0xDE80 } },
+ { 0x00010300, { 0xD800, 0xDF00 } },
+ { 0x000103FF, { 0xD800, 0xDFFF } },
+ { 0x00010400, { 0xD801, 0xDC00 } },
+ { 0x00010401, { 0xD801, 0xDC01 } },
+ { 0x00010402, { 0xD801, 0xDC02 } },
+ { 0x00010404, { 0xD801, 0xDC04 } },
+ { 0x00010408, { 0xD801, 0xDC08 } },
+ { 0x00010410, { 0xD801, 0xDC10 } },
+ { 0x00010420, { 0xD801, 0xDC20 } },
+ { 0x00010440, { 0xD801, 0xDC40 } },
+ { 0x00010480, { 0xD801, 0xDC80 } },
+ { 0x00010500, { 0xD801, 0xDD00 } },
+ { 0x00010600, { 0xD801, 0xDE00 } },
+ { 0x000107FF, { 0xD801, 0xDFFF } },
+ { 0x00010800, { 0xD802, 0xDC00 } },
+ { 0x00010801, { 0xD802, 0xDC01 } },
+ { 0x00010802, { 0xD802, 0xDC02 } },
+ { 0x00010804, { 0xD802, 0xDC04 } },
+ { 0x00010808, { 0xD802, 0xDC08 } },
+ { 0x00010810, { 0xD802, 0xDC10 } },
+ { 0x00010820, { 0xD802, 0xDC20 } },
+ { 0x00010840, { 0xD802, 0xDC40 } },
+ { 0x00010880, { 0xD802, 0xDC80 } },
+ { 0x00010900, { 0xD802, 0xDD00 } },
+ { 0x00010A00, { 0xD802, 0xDE00 } },
+ { 0x00010C00, { 0xD803, 0xDC00 } },
+ { 0x00010FFF, { 0xD803, 0xDFFF } },
+ { 0x00011000, { 0xD804, 0xDC00 } },
+ { 0x00011001, { 0xD804, 0xDC01 } },
+ { 0x00011002, { 0xD804, 0xDC02 } },
+ { 0x00011004, { 0xD804, 0xDC04 } },
+ { 0x00011008, { 0xD804, 0xDC08 } },
+ { 0x00011010, { 0xD804, 0xDC10 } },
+ { 0x00011020, { 0xD804, 0xDC20 } },
+ { 0x00011040, { 0xD804, 0xDC40 } },
+ { 0x00011080, { 0xD804, 0xDC80 } },
+ { 0x00011100, { 0xD804, 0xDD00 } },
+ { 0x00011200, { 0xD804, 0xDE00 } },
+ { 0x00011400, { 0xD805, 0xDC00 } },
+ { 0x00011800, { 0xD806, 0xDC00 } },
+ { 0x00011FFF, { 0xD807, 0xDFFF } },
+ { 0x00012000, { 0xD808, 0xDC00 } },
+ { 0x00012001, { 0xD808, 0xDC01 } },
+ { 0x00012002, { 0xD808, 0xDC02 } },
+ { 0x00012004, { 0xD808, 0xDC04 } },
+ { 0x00012008, { 0xD808, 0xDC08 } },
+ { 0x00012010, { 0xD808, 0xDC10 } },
+ { 0x00012020, { 0xD808, 0xDC20 } },
+ { 0x00012040, { 0xD808, 0xDC40 } },
+ { 0x00012080, { 0xD808, 0xDC80 } },
+ { 0x00012100, { 0xD808, 0xDD00 } },
+ { 0x00012200, { 0xD808, 0xDE00 } },
+ { 0x00012400, { 0xD809, 0xDC00 } },
+ { 0x00012800, { 0xD80A, 0xDC00 } },
+ { 0x00013000, { 0xD80C, 0xDC00 } },
+ { 0x00013FFF, { 0xD80F, 0xDFFF } },
+ { 0x00014000, { 0xD810, 0xDC00 } },
+ { 0x00014001, { 0xD810, 0xDC01 } },
+ { 0x00014002, { 0xD810, 0xDC02 } },
+ { 0x00014004, { 0xD810, 0xDC04 } },
+ { 0x00014008, { 0xD810, 0xDC08 } },
+ { 0x00014010, { 0xD810, 0xDC10 } },
+ { 0x00014020, { 0xD810, 0xDC20 } },
+ { 0x00014040, { 0xD810, 0xDC40 } },
+ { 0x00014080, { 0xD810, 0xDC80 } },
+ { 0x00014100, { 0xD810, 0xDD00 } },
+ { 0x00014200, { 0xD810, 0xDE00 } },
+ { 0x00014400, { 0xD811, 0xDC00 } },
+ { 0x00014800, { 0xD812, 0xDC00 } },
+ { 0x00015000, { 0xD814, 0xDC00 } },
+ { 0x00016000, { 0xD818, 0xDC00 } },
+ { 0x00017FFF, { 0xD81F, 0xDFFF } },
+ { 0x00018000, { 0xD820, 0xDC00 } },
+ { 0x00018001, { 0xD820, 0xDC01 } },
+ { 0x00018002, { 0xD820, 0xDC02 } },
+ { 0x00018004, { 0xD820, 0xDC04 } },
+ { 0x00018008, { 0xD820, 0xDC08 } },
+ { 0x00018010, { 0xD820, 0xDC10 } },
+ { 0x00018020, { 0xD820, 0xDC20 } },
+ { 0x00018040, { 0xD820, 0xDC40 } },
+ { 0x00018080, { 0xD820, 0xDC80 } },
+ { 0x00018100, { 0xD820, 0xDD00 } },
+ { 0x00018200, { 0xD820, 0xDE00 } },
+ { 0x00018400, { 0xD821, 0xDC00 } },
+ { 0x00018800, { 0xD822, 0xDC00 } },
+ { 0x00019000, { 0xD824, 0xDC00 } },
+ { 0x0001A000, { 0xD828, 0xDC00 } },
+ { 0x0001C000, { 0xD830, 0xDC00 } },
+ { 0x0001FFFF, { 0xD83F, 0xDFFF } },
+ { 0x00020000, { 0xD840, 0xDC00 } },
+ { 0x00020001, { 0xD840, 0xDC01 } },
+ { 0x00020002, { 0xD840, 0xDC02 } },
+ { 0x00020004, { 0xD840, 0xDC04 } },
+ { 0x00020008, { 0xD840, 0xDC08 } },
+ { 0x00020010, { 0xD840, 0xDC10 } },
+ { 0x00020020, { 0xD840, 0xDC20 } },
+ { 0x00020040, { 0xD840, 0xDC40 } },
+ { 0x00020080, { 0xD840, 0xDC80 } },
+ { 0x00020100, { 0xD840, 0xDD00 } },
+ { 0x00020200, { 0xD840, 0xDE00 } },
+ { 0x00020400, { 0xD841, 0xDC00 } },
+ { 0x00020800, { 0xD842, 0xDC00 } },
+ { 0x00021000, { 0xD844, 0xDC00 } },
+ { 0x00022000, { 0xD848, 0xDC00 } },
+ { 0x00024000, { 0xD850, 0xDC00 } },
+ { 0x00028000, { 0xD860, 0xDC00 } },
+ { 0x0002FFFF, { 0xD87F, 0xDFFF } },
+ { 0x00030000, { 0xD880, 0xDC00 } },
+ { 0x00030001, { 0xD880, 0xDC01 } },
+ { 0x00030002, { 0xD880, 0xDC02 } },
+ { 0x00030004, { 0xD880, 0xDC04 } },
+ { 0x00030008, { 0xD880, 0xDC08 } },
+ { 0x00030010, { 0xD880, 0xDC10 } },
+ { 0x00030020, { 0xD880, 0xDC20 } },
+ { 0x00030040, { 0xD880, 0xDC40 } },
+ { 0x00030080, { 0xD880, 0xDC80 } },
+ { 0x00030100, { 0xD880, 0xDD00 } },
+ { 0x00030200, { 0xD880, 0xDE00 } },
+ { 0x00030400, { 0xD881, 0xDC00 } },
+ { 0x00030800, { 0xD882, 0xDC00 } },
+ { 0x00031000, { 0xD884, 0xDC00 } },
+ { 0x00032000, { 0xD888, 0xDC00 } },
+ { 0x00034000, { 0xD890, 0xDC00 } },
+ { 0x00038000, { 0xD8A0, 0xDC00 } },
+ { 0x0003FFFF, { 0xD8BF, 0xDFFF } },
+ { 0x00040000, { 0xD8C0, 0xDC00 } },
+ { 0x00040001, { 0xD8C0, 0xDC01 } },
+ { 0x00040002, { 0xD8C0, 0xDC02 } },
+ { 0x00040004, { 0xD8C0, 0xDC04 } },
+ { 0x00040008, { 0xD8C0, 0xDC08 } },
+ { 0x00040010, { 0xD8C0, 0xDC10 } },
+ { 0x00040020, { 0xD8C0, 0xDC20 } },
+ { 0x00040040, { 0xD8C0, 0xDC40 } },
+ { 0x00040080, { 0xD8C0, 0xDC80 } },
+ { 0x00040100, { 0xD8C0, 0xDD00 } },
+ { 0x00040200, { 0xD8C0, 0xDE00 } },
+ { 0x00040400, { 0xD8C1, 0xDC00 } },
+ { 0x00040800, { 0xD8C2, 0xDC00 } },
+ { 0x00041000, { 0xD8C4, 0xDC00 } },
+ { 0x00042000, { 0xD8C8, 0xDC00 } },
+ { 0x00044000, { 0xD8D0, 0xDC00 } },
+ { 0x00048000, { 0xD8E0, 0xDC00 } },
+ { 0x0004FFFF, { 0xD8FF, 0xDFFF } },
+ { 0x00050000, { 0xD900, 0xDC00 } },
+ { 0x00050001, { 0xD900, 0xDC01 } },
+ { 0x00050002, { 0xD900, 0xDC02 } },
+ { 0x00050004, { 0xD900, 0xDC04 } },
+ { 0x00050008, { 0xD900, 0xDC08 } },
+ { 0x00050010, { 0xD900, 0xDC10 } },
+ { 0x00050020, { 0xD900, 0xDC20 } },
+ { 0x00050040, { 0xD900, 0xDC40 } },
+ { 0x00050080, { 0xD900, 0xDC80 } },
+ { 0x00050100, { 0xD900, 0xDD00 } },
+ { 0x00050200, { 0xD900, 0xDE00 } },
+ { 0x00050400, { 0xD901, 0xDC00 } },
+ { 0x00050800, { 0xD902, 0xDC00 } },
+ { 0x00051000, { 0xD904, 0xDC00 } },
+ { 0x00052000, { 0xD908, 0xDC00 } },
+ { 0x00054000, { 0xD910, 0xDC00 } },
+ { 0x00058000, { 0xD920, 0xDC00 } },
+ { 0x00060000, { 0xD940, 0xDC00 } },
+ { 0x00070000, { 0xD980, 0xDC00 } },
+ { 0x0007FFFF, { 0xD9BF, 0xDFFF } },
+ { 0x00080000, { 0xD9C0, 0xDC00 } },
+ { 0x00080001, { 0xD9C0, 0xDC01 } },
+ { 0x00080002, { 0xD9C0, 0xDC02 } },
+ { 0x00080004, { 0xD9C0, 0xDC04 } },
+ { 0x00080008, { 0xD9C0, 0xDC08 } },
+ { 0x00080010, { 0xD9C0, 0xDC10 } },
+ { 0x00080020, { 0xD9C0, 0xDC20 } },
+ { 0x00080040, { 0xD9C0, 0xDC40 } },
+ { 0x00080080, { 0xD9C0, 0xDC80 } },
+ { 0x00080100, { 0xD9C0, 0xDD00 } },
+ { 0x00080200, { 0xD9C0, 0xDE00 } },
+ { 0x00080400, { 0xD9C1, 0xDC00 } },
+ { 0x00080800, { 0xD9C2, 0xDC00 } },
+ { 0x00081000, { 0xD9C4, 0xDC00 } },
+ { 0x00082000, { 0xD9C8, 0xDC00 } },
+ { 0x00084000, { 0xD9D0, 0xDC00 } },
+ { 0x00088000, { 0xD9E0, 0xDC00 } },
+ { 0x0008FFFF, { 0xD9FF, 0xDFFF } },
+ { 0x00090000, { 0xDA00, 0xDC00 } },
+ { 0x00090001, { 0xDA00, 0xDC01 } },
+ { 0x00090002, { 0xDA00, 0xDC02 } },
+ { 0x00090004, { 0xDA00, 0xDC04 } },
+ { 0x00090008, { 0xDA00, 0xDC08 } },
+ { 0x00090010, { 0xDA00, 0xDC10 } },
+ { 0x00090020, { 0xDA00, 0xDC20 } },
+ { 0x00090040, { 0xDA00, 0xDC40 } },
+ { 0x00090080, { 0xDA00, 0xDC80 } },
+ { 0x00090100, { 0xDA00, 0xDD00 } },
+ { 0x00090200, { 0xDA00, 0xDE00 } },
+ { 0x00090400, { 0xDA01, 0xDC00 } },
+ { 0x00090800, { 0xDA02, 0xDC00 } },
+ { 0x00091000, { 0xDA04, 0xDC00 } },
+ { 0x00092000, { 0xDA08, 0xDC00 } },
+ { 0x00094000, { 0xDA10, 0xDC00 } },
+ { 0x00098000, { 0xDA20, 0xDC00 } },
+ { 0x000A0000, { 0xDA40, 0xDC00 } },
+ { 0x000B0000, { 0xDA80, 0xDC00 } },
+ { 0x000C0000, { 0xDAC0, 0xDC00 } },
+ { 0x000D0000, { 0xDB00, 0xDC00 } },
+ { 0x000FFFFF, { 0xDBBF, 0xDFFF } },
+ { 0x0010FFFF, { 0xDBFF, 0xDFFF } }
+
+};
+
+/* illegal utf8 sequences */
+char *utf8_bad[] = {
+ "\xC0\x80",
+ "\xC1\xBF",
+ "\xE0\x80\x80",
+ "\xE0\x9F\xBF",
+ "\xF0\x80\x80\x80",
+ "\xF0\x8F\xBF\xBF",
+ "\xF4\x90\x80\x80",
+ "\xF7\xBF\xBF\xBF",
+ "\xF8\x80\x80\x80\x80",
+ "\xF8\x88\x80\x80\x80",
+ "\xF8\x92\x80\x80\x80",
+ "\xF8\x9F\xBF\xBF\xBF",
+ "\xF8\xA0\x80\x80\x80",
+ "\xF8\xA8\x80\x80\x80",
+ "\xF8\xB0\x80\x80\x80",
+ "\xF8\xBF\xBF\xBF\xBF",
+ "\xF9\x80\x80\x80\x88",
+ "\xF9\x84\x80\x80\x80",
+ "\xF9\xBF\xBF\xBF\xBF",
+ "\xFA\x80\x80\x80\x80",
+ "\xFA\x90\x80\x80\x80",
+ "\xFB\xBF\xBF\xBF\xBF",
+ "\xFC\x84\x80\x80\x80\x81",
+ "\xFC\x85\x80\x80\x80\x80",
+ "\xFC\x86\x80\x80\x80\x80",
+ "\xFC\x87\xBF\xBF\xBF\xBF",
+ "\xFC\x88\xA0\x80\x80\x80",
+ "\xFC\x89\x80\x80\x80\x80",
+ "\xFC\x8A\x80\x80\x80\x80",
+ "\xFC\x90\x80\x80\x80\x82",
+ "\xFD\x80\x80\x80\x80\x80",
+ "\xFD\xBF\xBF\xBF\xBF\xBF",
+ "\x80",
+ "\xC3",
+ "\xC3\xC3\x80",
+ "\xED\xA0\x80",
+ "\xED\xBF\x80",
+ "\xED\xBF\xBF",
+ "\xED\xA0\x80\xE0\xBF\xBF",
+};
+
+static void
+dump_utf8
+(
+ char *word,
+ unsigned char *utf8,
+ char *end
+)
+{
+ fprintf(stdout, "%s ", word);
+ for( ; *utf8; utf8++ ) {
+ fprintf(stdout, "%02.2x ", (unsigned int)*utf8);
+ }
+ fprintf(stdout, "%s", end);
+}
+
+static PRBool
+test_ucs4_chars
+(
+ void
+)
+{
+ PRBool rv = PR_TRUE;
+ int i;
+
+ for( i = 0; i < sizeof(ucs4)/sizeof(ucs4[0]); i++ ) {
+ struct ucs4 *e = &ucs4[i];
+ PRBool result;
+ unsigned char utf8[8];
+ unsigned int len = 0;
+ PRUint32 back = 0;
+
+ (void)memset(utf8, 0, sizeof(utf8));
+
+ result = sec_port_ucs4_utf8_conversion_function(PR_FALSE,
+ (unsigned char *)&e->c, sizeof(e->c), utf8, sizeof(utf8), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert UCS-4 0x%08.8x to UTF-8\n", e->c);
+ rv = PR_FALSE;
+ continue;
+ }
+
+ if( (len >= sizeof(utf8)) ||
+ (strlen(e->utf8) != len) ||
+ (utf8[len] = '\0', 0 != strcmp(e->utf8, utf8)) ) {
+ fprintf(stdout, "Wrong conversion of UCS-4 0x%08.8x to UTF-8: ", e->c);
+ dump_utf8("expected", e->utf8, ", ");
+ dump_utf8("received", utf8, "\n");
+ rv = PR_FALSE;
+ continue;
+ }
+
+ result = sec_port_ucs4_utf8_conversion_function(PR_TRUE,
+ utf8, len, (unsigned char *)&back, sizeof(back), &len);
+
+ if( !result ) {
+ dump_utf8("Failed to convert UTF-8", utf8, "to UCS-4\n");
+ rv = PR_FALSE;
+ continue;
+ }
+
+ if( (sizeof(back) != len) || (e->c != back) ) {
+ dump_utf8("Wrong conversion of UTF-8", utf8, " to UCS-4:");
+ fprintf(stdout, "expected 0x%08.8x, received 0x%08.8x\n", e->c, back);
+ rv = PR_FALSE;
+ continue;
+ }
+ }
+
+ return rv;
+}
+
+static PRBool
+test_ucs2_chars
+(
+ void
+)
+{
+ PRBool rv = PR_TRUE;
+ int i;
+
+ for( i = 0; i < sizeof(ucs2)/sizeof(ucs2[0]); i++ ) {
+ struct ucs2 *e = &ucs2[i];
+ PRBool result;
+ unsigned char utf8[8];
+ unsigned int len = 0;
+ PRUint16 back = 0;
+
+ (void)memset(utf8, 0, sizeof(utf8));
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_FALSE,
+ (unsigned char *)&e->c, sizeof(e->c), utf8, sizeof(utf8), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert UCS-2 0x%04.4x to UTF-8\n", e->c);
+ rv = PR_FALSE;
+ continue;
+ }
+
+ if( (len >= sizeof(utf8)) ||
+ (strlen(e->utf8) != len) ||
+ (utf8[len] = '\0', 0 != strcmp(e->utf8, utf8)) ) {
+ fprintf(stdout, "Wrong conversion of UCS-2 0x%04.4x to UTF-8: ", e->c);
+ dump_utf8("expected", e->utf8, ", ");
+ dump_utf8("received", utf8, "\n");
+ rv = PR_FALSE;
+ continue;
+ }
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_TRUE,
+ utf8, len, (unsigned char *)&back, sizeof(back), &len);
+
+ if( !result ) {
+ dump_utf8("Failed to convert UTF-8", utf8, "to UCS-2\n");
+ rv = PR_FALSE;
+ continue;
+ }
+
+ if( (sizeof(back) != len) || (e->c != back) ) {
+ dump_utf8("Wrong conversion of UTF-8", utf8, "to UCS-2:");
+ fprintf(stdout, "expected 0x%08.8x, received 0x%08.8x\n", e->c, back);
+ rv = PR_FALSE;
+ continue;
+ }
+ }
+
+ return rv;
+}
+
+static PRBool
+test_utf16_chars
+(
+ void
+)
+{
+ PRBool rv = PR_TRUE;
+ int i;
+
+ for( i = 0; i < sizeof(utf16)/sizeof(utf16[0]); i++ ) {
+ struct utf16 *e = &utf16[i];
+ PRBool result;
+ unsigned char utf8[8];
+ unsigned int len = 0;
+ PRUint32 back32 = 0;
+ PRUint16 back[2];
+
+ (void)memset(utf8, 0, sizeof(utf8));
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_FALSE,
+ (unsigned char *)&e->w[0], sizeof(e->w), utf8, sizeof(utf8), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert UTF-16 0x%04.4x 0x%04.4x to UTF-8\n",
+ e->w[0], e->w[1]);
+ rv = PR_FALSE;
+ continue;
+ }
+
+ result = sec_port_ucs4_utf8_conversion_function(PR_TRUE,
+ utf8, len, (unsigned char *)&back32, sizeof(back32), &len);
+
+ if( 4 != len ) {
+ fprintf(stdout, "Failed to convert UTF-16 0x%04.4x 0x%04.4x to UTF-8: "
+ "unexpected len %d\n", e->w[0], e->w[1], len);
+ rv = PR_FALSE;
+ continue;
+ }
+
+ utf8[len] = '\0'; /* null-terminate for printing */
+
+ if( !result ) {
+ dump_utf8("Failed to convert UTF-8", utf8, "to UCS-4 (utf-16 test)\n");
+ rv = PR_FALSE;
+ continue;
+ }
+
+ if( (sizeof(back32) != len) || (e->c != back32) ) {
+ fprintf(stdout, "Wrong conversion of UTF-16 0x%04.4x 0x%04.4x ",
+ e->w[0], e->w[1]);
+ dump_utf8("to UTF-8", utf8, "and then to UCS-4: ");
+ if( sizeof(back32) != len ) {
+ fprintf(stdout, "len is %d\n", len);
+ } else {
+ fprintf(stdout, "expected 0x%08.8x, received 0x%08.8x\n", e->c, back32);
+ }
+ rv = PR_FALSE;
+ continue;
+ }
+
+ (void)memset(utf8, 0, sizeof(utf8));
+ back[0] = back[1] = 0;
+
+ result = sec_port_ucs4_utf8_conversion_function(PR_FALSE,
+ (unsigned char *)&e->c, sizeof(e->c), utf8, sizeof(utf8), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert UCS-4 0x%08.8x to UTF-8 (utf-16 test)\n",
+ e->c);
+ rv = PR_FALSE;
+ continue;
+ }
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_TRUE,
+ utf8, len, (unsigned char *)&back[0], sizeof(back), &len);
+
+ if( 4 != len ) {
+ fprintf(stdout, "Failed to convert UCS-4 0x%08.8x to UTF-8: "
+ "unexpected len %d\n", e->c, len);
+ rv = PR_FALSE;
+ continue;
+ }
+
+ utf8[len] = '\0'; /* null-terminate for printing */
+
+ if( !result ) {
+ dump_utf8("Failed to convert UTF-8", utf8, "to UTF-16\n");
+ rv = PR_FALSE;
+ continue;
+ }
+
+ if( (sizeof(back) != len) || (e->w[0] != back[0]) || (e->w[1] != back[1]) ) {
+ fprintf(stdout, "Wrong conversion of UCS-4 0x%08.8x to UTF-8", e->c);
+ dump_utf8("", utf8, "and then to UTF-16:");
+ if( sizeof(back) != len ) {
+ fprintf(stdout, "len is %d\n", len);
+ } else {
+ fprintf(stdout, "expected 0x%04.4x 0x%04.4x, received 0x%04.4x 0x%04.4xx\n",
+ e->w[0], e->w[1], back[0], back[1]);
+ }
+ rv = PR_FALSE;
+ continue;
+ }
+ }
+
+ return rv;
+}
+
+static PRBool
+test_utf8_bad_chars
+(
+ void
+)
+{
+ PRBool rv = PR_TRUE;
+ int i;
+
+ for( i = 0; i < sizeof(utf8_bad)/sizeof(utf8_bad[0]); i++ ) {
+ PRBool result;
+ unsigned char destbuf[30];
+ unsigned int len = 0;
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_TRUE,
+ (unsigned char *)utf8_bad[i], strlen(utf8_bad[i]), destbuf, sizeof(destbuf), &len);
+
+ if( result ) {
+ dump_utf8("Failed to detect bad UTF-8 string converting to UCS2: ", utf8_bad[i], "\n");
+ rv = PR_FALSE;
+ continue;
+ }
+ result = sec_port_ucs4_utf8_conversion_function(PR_TRUE,
+ (unsigned char *)utf8_bad[i], strlen(utf8_bad[i]), destbuf, sizeof(destbuf), &len);
+
+ if( result ) {
+ dump_utf8("Failed to detect bad UTF-8 string converting to UCS4: ", utf8_bad[i], "\n");
+ rv = PR_FALSE;
+ continue;
+ }
+
+ }
+
+ return rv;
+}
+
+static PRBool
+test_iso88591_chars
+(
+ void
+)
+{
+ PRBool rv = PR_TRUE;
+ int i;
+
+ for( i = 0; i < sizeof(ucs2)/sizeof(ucs2[0]); i++ ) {
+ struct ucs2 *e = &ucs2[i];
+ PRBool result;
+ unsigned char iso88591;
+ unsigned char utf8[3];
+ unsigned int len = 0;
+
+ if (ntohs(e->c) > 0xFF) continue;
+
+ (void)memset(utf8, 0, sizeof(utf8));
+ iso88591 = ntohs(e->c);
+
+ result = sec_port_iso88591_utf8_conversion_function(&iso88591,
+ 1, utf8, sizeof(utf8), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert ISO-8859-1 0x%02.2x to UTF-8\n", iso88591);
+ rv = PR_FALSE;
+ continue;
+ }
+
+ if( (len >= sizeof(utf8)) ||
+ (strlen(e->utf8) != len) ||
+ (utf8[len] = '\0', 0 != strcmp(e->utf8, utf8)) ) {
+ fprintf(stdout, "Wrong conversion of ISO-8859-1 0x%02.2x to UTF-8: ", iso88591);
+ dump_utf8("expected", e->utf8, ", ");
+ dump_utf8("received", utf8, "\n");
+ rv = PR_FALSE;
+ continue;
+ }
+
+ }
+
+ return rv;
+}
+
+static PRBool
+test_zeroes
+(
+ void
+)
+{
+ PRBool rv = PR_TRUE;
+ PRBool result;
+ PRUint32 lzero = 0;
+ PRUint16 szero = 0;
+ unsigned char utf8[8];
+ unsigned int len = 0;
+ PRUint32 lback = 1;
+ PRUint16 sback = 1;
+
+ (void)memset(utf8, 1, sizeof(utf8));
+
+ result = sec_port_ucs4_utf8_conversion_function(PR_FALSE,
+ (unsigned char *)&lzero, sizeof(lzero), utf8, sizeof(utf8), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert UCS-4 0x00000000 to UTF-8\n");
+ rv = PR_FALSE;
+ } else if( 1 != len ) {
+ fprintf(stdout, "Wrong conversion of UCS-4 0x00000000: len = %d\n", len);
+ rv = PR_FALSE;
+ } else if( '\0' != *utf8 ) {
+ fprintf(stdout, "Wrong conversion of UCS-4 0x00000000: expected 00 ,"
+ "received %02.2x\n", (unsigned int)*utf8);
+ rv = PR_FALSE;
+ }
+
+ result = sec_port_ucs4_utf8_conversion_function(PR_TRUE,
+ "", 1, (unsigned char *)&lback, sizeof(lback), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert UTF-8 00 to UCS-4\n");
+ rv = PR_FALSE;
+ } else if( 4 != len ) {
+ fprintf(stdout, "Wrong conversion of UTF-8 00 to UCS-4: len = %d\n", len);
+ rv = PR_FALSE;
+ } else if( 0 != lback ) {
+ fprintf(stdout, "Wrong conversion of UTF-8 00 to UCS-4: "
+ "expected 0x00000000, received 0x%08.8x\n", lback);
+ rv = PR_FALSE;
+ }
+
+ (void)memset(utf8, 1, sizeof(utf8));
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_FALSE,
+ (unsigned char *)&szero, sizeof(szero), utf8, sizeof(utf8), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert UCS-2 0x0000 to UTF-8\n");
+ rv = PR_FALSE;
+ } else if( 1 != len ) {
+ fprintf(stdout, "Wrong conversion of UCS-2 0x0000: len = %d\n", len);
+ rv = PR_FALSE;
+ } else if( '\0' != *utf8 ) {
+ fprintf(stdout, "Wrong conversion of UCS-2 0x0000: expected 00 ,"
+ "received %02.2x\n", (unsigned int)*utf8);
+ rv = PR_FALSE;
+ }
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_TRUE,
+ "", 1, (unsigned char *)&sback, sizeof(sback), &len);
+
+ if( !result ) {
+ fprintf(stdout, "Failed to convert UTF-8 00 to UCS-2\n");
+ rv = PR_FALSE;
+ } else if( 2 != len ) {
+ fprintf(stdout, "Wrong conversion of UTF-8 00 to UCS-2: len = %d\n", len);
+ rv = PR_FALSE;
+ } else if( 0 != sback ) {
+ fprintf(stdout, "Wrong conversion of UTF-8 00 to UCS-2: "
+ "expected 0x0000, received 0x%04.4x\n", sback);
+ rv = PR_FALSE;
+ }
+
+ return rv;
+}
+
+static PRBool
+test_multichars
+(
+ void
+)
+{
+ int i;
+ unsigned int len, lenout;
+ PRUint32 *ucs4s;
+ char *ucs4_utf8;
+ PRUint16 *ucs2s;
+ char *ucs2_utf8;
+ void *tmp;
+ PRBool result;
+
+ ucs4s = (PRUint32 *)calloc(sizeof(ucs4)/sizeof(ucs4[0]), sizeof(PRUint32));
+ ucs2s = (PRUint16 *)calloc(sizeof(ucs2)/sizeof(ucs2[0]), sizeof(PRUint16));
+
+ if( ((PRUint32 *)NULL == ucs4s) || ((PRUint16 *)NULL == ucs2s) ) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ len = 0;
+ for( i = 0; i < sizeof(ucs4)/sizeof(ucs4[0]); i++ ) {
+ ucs4s[i] = ucs4[i].c;
+ len += strlen(ucs4[i].utf8);
+ }
+
+ ucs4_utf8 = (char *)malloc(len);
+
+ len = 0;
+ for( i = 0; i < sizeof(ucs2)/sizeof(ucs2[0]); i++ ) {
+ ucs2s[i] = ucs2[i].c;
+ len += strlen(ucs2[i].utf8);
+ }
+
+ ucs2_utf8 = (char *)malloc(len);
+
+ if( ((char *)NULL == ucs4_utf8) || ((char *)NULL == ucs2_utf8) ) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ *ucs4_utf8 = '\0';
+ for( i = 0; i < sizeof(ucs4)/sizeof(ucs4[0]); i++ ) {
+ strcat(ucs4_utf8, ucs4[i].utf8);
+ }
+
+ *ucs2_utf8 = '\0';
+ for( i = 0; i < sizeof(ucs2)/sizeof(ucs2[0]); i++ ) {
+ strcat(ucs2_utf8, ucs2[i].utf8);
+ }
+
+ /* UTF-8 -> UCS-4 */
+ len = sizeof(ucs4)/sizeof(ucs4[0]) * sizeof(PRUint32);
+ tmp = calloc(len, 1);
+ if( (void *)NULL == tmp ) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ result = sec_port_ucs4_utf8_conversion_function(PR_TRUE,
+ ucs4_utf8, strlen(ucs4_utf8), tmp, len, &lenout);
+ if( !result ) {
+ fprintf(stdout, "Failed to convert much UTF-8 to UCS-4\n");
+ goto done;
+ }
+
+ if( lenout != len ) {
+ fprintf(stdout, "Unexpected length converting much UTF-8 to UCS-4\n");
+ goto loser;
+ }
+
+ if( 0 != memcmp(ucs4s, tmp, len) ) {
+ fprintf(stdout, "Wrong conversion of much UTF-8 to UCS-4\n");
+ goto loser;
+ }
+
+ free(tmp); tmp = (void *)NULL;
+
+ /* UCS-4 -> UTF-8 */
+ len = strlen(ucs4_utf8);
+ tmp = calloc(len, 1);
+ if( (void *)NULL == tmp ) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ result = sec_port_ucs4_utf8_conversion_function(PR_FALSE,
+ (unsigned char *)ucs4s, sizeof(ucs4)/sizeof(ucs4[0]) * sizeof(PRUint32),
+ tmp, len, &lenout);
+ if( !result ) {
+ fprintf(stdout, "Failed to convert much UCS-4 to UTF-8\n");
+ goto done;
+ }
+
+ if( lenout != len ) {
+ fprintf(stdout, "Unexpected length converting much UCS-4 to UTF-8\n");
+ goto loser;
+ }
+
+ if( 0 != strncmp(ucs4_utf8, tmp, len) ) {
+ fprintf(stdout, "Wrong conversion of much UCS-4 to UTF-8\n");
+ goto loser;
+ }
+
+ free(tmp); tmp = (void *)NULL;
+
+ /* UTF-8 -> UCS-2 */
+ len = sizeof(ucs2)/sizeof(ucs2[0]) * sizeof(PRUint16);
+ tmp = calloc(len, 1);
+ if( (void *)NULL == tmp ) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_TRUE,
+ ucs2_utf8, strlen(ucs2_utf8), tmp, len, &lenout);
+ if( !result ) {
+ fprintf(stdout, "Failed to convert much UTF-8 to UCS-2\n");
+ goto done;
+ }
+
+ if( lenout != len ) {
+ fprintf(stdout, "Unexpected length converting much UTF-8 to UCS-2\n");
+ goto loser;
+ }
+
+ if( 0 != memcmp(ucs2s, tmp, len) ) {
+ fprintf(stdout, "Wrong conversion of much UTF-8 to UCS-2\n");
+ goto loser;
+ }
+
+ free(tmp); tmp = (void *)NULL;
+
+ /* UCS-2 -> UTF-8 */
+ len = strlen(ucs2_utf8);
+ tmp = calloc(len, 1);
+ if( (void *)NULL == tmp ) {
+ fprintf(stderr, "out of memory\n");
+ exit(1);
+ }
+
+ result = sec_port_ucs2_utf8_conversion_function(PR_FALSE,
+ (unsigned char *)ucs2s, sizeof(ucs2)/sizeof(ucs2[0]) * sizeof(PRUint16),
+ tmp, len, &lenout);
+ if( !result ) {
+ fprintf(stdout, "Failed to convert much UCS-2 to UTF-8\n");
+ goto done;
+ }
+
+ if( lenout != len ) {
+ fprintf(stdout, "Unexpected length converting much UCS-2 to UTF-8\n");
+ goto loser;
+ }
+
+ if( 0 != strncmp(ucs2_utf8, tmp, len) ) {
+ fprintf(stdout, "Wrong conversion of much UCS-2 to UTF-8\n");
+ goto loser;
+ }
+
+ /* implement UTF16 */
+
+ result = PR_TRUE;
+ goto done;
+
+ loser:
+ result = PR_FALSE;
+ done:
+ free(ucs4s);
+ free(ucs4_utf8);
+ free(ucs2s);
+ free(ucs2_utf8);
+ if( (void *)NULL != tmp ) free(tmp);
+ return result;
+}
+
+void
+byte_order
+(
+ void
+)
+{
+ /*
+ * The implementation (now) expects the 16- and 32-bit characters
+ * to be in network byte order, not host byte order. Therefore I
+ * have to byteswap all those test vectors above. hton[ls] may be
+ * functions, so I have to do this dynamically. If you want to
+ * use this code to do host byte order conversions, just remove
+ * the call in main() to this function.
+ */
+
+ int i;
+
+ for( i = 0; i < sizeof(ucs4)/sizeof(ucs4[0]); i++ ) {
+ struct ucs4 *e = &ucs4[i];
+ e->c = htonl(e->c);
+ }
+
+ for( i = 0; i < sizeof(ucs2)/sizeof(ucs2[0]); i++ ) {
+ struct ucs2 *e = &ucs2[i];
+ e->c = htons(e->c);
+ }
+
+ for( i = 0; i < sizeof(utf16)/sizeof(utf16[0]); i++ ) {
+ struct utf16 *e = &utf16[i];
+ e->c = htonl(e->c);
+ e->w[0] = htons(e->w[0]);
+ e->w[1] = htons(e->w[1]);
+ }
+
+ return;
+}
+
+int
+main
+(
+ int argc,
+ char *argv[]
+)
+{
+ byte_order();
+
+ if( test_ucs4_chars() &&
+ test_ucs2_chars() &&
+ test_utf16_chars() &&
+ test_utf8_bad_chars() &&
+ test_iso88591_chars() &&
+ test_zeroes() &&
+ test_multichars() &&
+ PR_TRUE ) {
+ fprintf(stderr, "PASS\n");
+ return 1;
+ } else {
+ fprintf(stderr, "FAIL\n");
+ return 0;
+ }
+}
+
+#endif /* TEST_UTF8 */
diff --git a/security/nss/lib/util/utilrename.h b/security/nss/lib/util/utilrename.h
new file mode 100644
index 000000000..ee5ae6733
--- /dev/null
+++ b/security/nss/lib/util/utilrename.h
@@ -0,0 +1,194 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License") you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Network Security Services libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Sun Microsystems, Inc.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+/*
+ * utilrename.h - rename symbols moved from libnss3 to libnssutil3
+ *
+ */
+
+#ifndef _LIBUTIL_H_
+#define _LIBUTIL_H_ _LIBUTIL_H__Util
+
+#ifdef USE_UTIL_DIRECTLY
+
+/* functions moved from libnss3 */
+#define ATOB_AsciiToData ATOB_AsciiToData_Util
+#define ATOB_ConvertAsciiToItem ATOB_ConvertAsciiToItem_Util
+#define BTOA_ConvertItemToAscii BTOA_ConvertItemToAscii_Util
+#define BTOA_DataToAscii BTOA_DataToAscii_Util
+#define CERT_GenTime2FormattedAscii CERT_GenTime2FormattedAscii_Util
+#define DER_AsciiToTime DER_AsciiToTime_Util
+#define DER_DecodeTimeChoice DER_DecodeTimeChoice_Util
+#define DER_Encode DER_Encode_Util
+#define DER_EncodeTimeChoice DER_EncodeTimeChoice_Util
+#define DER_GeneralizedDayToAscii DER_GeneralizedDayToAscii_Util
+#define DER_GeneralizedTimeToTime DER_GeneralizedTimeToTime_Util
+#define DER_GetInteger DER_GetInteger_Util
+#define DER_Lengths DER_Lengths_Util
+#define DER_TimeChoiceDayToAscii DER_TimeChoiceDayToAscii_Util
+#define DER_TimeToGeneralizedTime DER_TimeToGeneralizedTime_Util
+#define DER_TimeToGeneralizedTimeArena DER_TimeToGeneralizedTimeArena_Util
+#define DER_TimeToUTCTime DER_TimeToUTCTime_Util
+#define DER_UTCDayToAscii DER_UTCDayToAscii_Util
+#define DER_UTCTimeToAscii DER_UTCTimeToAscii_Util
+#define DER_UTCTimeToTime DER_UTCTimeToTime_Util
+#define NSS_PutEnv NSS_PutEnv_Util
+#define NSSBase64_DecodeBuffer NSSBase64_DecodeBuffer_Util
+#define NSSBase64_EncodeItem NSSBase64_EncodeItem_Util
+#define NSSBase64Decoder_Create NSSBase64Decoder_Create_Util
+#define NSSBase64Decoder_Destroy NSSBase64Decoder_Destroy_Util
+#define NSSBase64Decoder_Update NSSBase64Decoder_Update_Util
+#define NSSBase64Encoder_Create NSSBase64Encoder_Create_Util
+#define NSSBase64Encoder_Destroy NSSBase64Encoder_Destroy_Util
+#define NSSBase64Encoder_Update NSSBase64Encoder_Update_Util
+#define NSSRWLock_Destroy NSSRWLock_Destroy_Util
+#define NSSRWLock_HaveWriteLock NSSRWLock_HaveWriteLock_Util
+#define NSSRWLock_LockRead NSSRWLock_LockRead_Util
+#define NSSRWLock_LockWrite NSSRWLock_LockWrite_Util
+#define NSSRWLock_New NSSRWLock_New_Util
+#define NSSRWLock_UnlockRead NSSRWLock_UnlockRead_Util
+#define NSSRWLock_UnlockWrite NSSRWLock_UnlockWrite_Util
+#define PORT_Alloc PORT_Alloc_Util
+#define PORT_ArenaAlloc PORT_ArenaAlloc_Util
+#define PORT_ArenaGrow PORT_ArenaGrow_Util
+#define PORT_ArenaMark PORT_ArenaMark_Util
+#define PORT_ArenaRelease PORT_ArenaRelease_Util
+#define PORT_ArenaStrdup PORT_ArenaStrdup_Util
+#define PORT_ArenaUnmark PORT_ArenaUnmark_Util
+#define PORT_ArenaZAlloc PORT_ArenaZAlloc_Util
+#define PORT_Free PORT_Free_Util
+#define PORT_FreeArena PORT_FreeArena_Util
+#define PORT_GetError PORT_GetError_Util
+#define PORT_NewArena PORT_NewArena_Util
+#define PORT_Realloc PORT_Realloc_Util
+#define PORT_SetError PORT_SetError_Util
+#define PORT_SetUCS2_ASCIIConversionFunction PORT_SetUCS2_ASCIIConversionFunction_Util
+#define PORT_SetUCS2_UTF8ConversionFunction PORT_SetUCS2_UTF8ConversionFunction_Util
+#define PORT_SetUCS4_UTF8ConversionFunction PORT_SetUCS4_UTF8ConversionFunction_Util
+#define PORT_Strdup PORT_Strdup_Util
+#define PORT_UCS2_ASCIIConversion PORT_UCS2_ASCIIConversion_Util
+#define PORT_UCS2_UTF8Conversion PORT_UCS2_UTF8Conversion_Util
+#define PORT_ZAlloc PORT_ZAlloc_Util
+#define PORT_ZFree PORT_ZFree_Util
+#define SEC_ASN1Decode SEC_ASN1Decode_Util
+#define SEC_ASN1DecodeInteger SEC_ASN1DecodeInteger_Util
+#define SEC_ASN1DecodeItem SEC_ASN1DecodeItem_Util
+#define SEC_ASN1DecoderAbort SEC_ASN1DecoderAbort_Util
+#define SEC_ASN1DecoderClearFilterProc SEC_ASN1DecoderClearFilterProc_Util
+#define SEC_ASN1DecoderClearNotifyProc SEC_ASN1DecoderClearNotifyProc_Util
+#define SEC_ASN1DecoderFinish SEC_ASN1DecoderFinish_Util
+#define SEC_ASN1DecoderSetFilterProc SEC_ASN1DecoderSetFilterProc_Util
+#define SEC_ASN1DecoderSetNotifyProc SEC_ASN1DecoderSetNotifyProc_Util
+#define SEC_ASN1DecoderStart SEC_ASN1DecoderStart_Util
+#define SEC_ASN1DecoderUpdate SEC_ASN1DecoderUpdate_Util
+#define SEC_ASN1Encode SEC_ASN1Encode_Util
+#define SEC_ASN1EncodeInteger SEC_ASN1EncodeInteger_Util
+#define SEC_ASN1EncodeItem SEC_ASN1EncodeItem_Util
+#define SEC_ASN1EncoderAbort SEC_ASN1EncoderAbort_Util
+#define SEC_ASN1EncoderClearNotifyProc SEC_ASN1EncoderClearNotifyProc_Util
+#define SEC_ASN1EncoderClearStreaming SEC_ASN1EncoderClearStreaming_Util
+#define SEC_ASN1EncoderClearTakeFromBuf SEC_ASN1EncoderClearTakeFromBuf_Util
+#define SEC_ASN1EncoderFinish SEC_ASN1EncoderFinish_Util
+#define SEC_ASN1EncoderSetNotifyProc SEC_ASN1EncoderSetNotifyProc_Util
+#define SEC_ASN1EncoderSetStreaming SEC_ASN1EncoderSetStreaming_Util
+#define SEC_ASN1EncoderSetTakeFromBuf SEC_ASN1EncoderSetTakeFromBuf_Util
+#define SEC_ASN1EncoderStart SEC_ASN1EncoderStart_Util
+#define SEC_ASN1EncoderUpdate SEC_ASN1EncoderUpdate_Util
+#define SEC_ASN1EncodeUnsignedInteger SEC_ASN1EncodeUnsignedInteger_Util
+#define SEC_ASN1LengthLength SEC_ASN1LengthLength_Util
+#define SEC_QuickDERDecodeItem SEC_QuickDERDecodeItem_Util
+#define SECITEM_AllocItem SECITEM_AllocItem_Util
+#define SECITEM_ArenaDupItem SECITEM_ArenaDupItem_Util
+#define SECITEM_CompareItem SECITEM_CompareItem_Util
+#define SECITEM_CopyItem SECITEM_CopyItem_Util
+#define SECITEM_DupItem SECITEM_DupItem_Util
+#define SECITEM_FreeItem SECITEM_FreeItem_Util
+#define SECITEM_ItemsAreEqual SECITEM_ItemsAreEqual_Util
+#define SECITEM_ZfreeItem SECITEM_ZfreeItem_Util
+#define SECOID_AddEntry SECOID_AddEntry_Util
+#define SECOID_CompareAlgorithmID SECOID_CompareAlgorithmID_Util
+#define SECOID_CopyAlgorithmID SECOID_CopyAlgorithmID_Util
+#define SECOID_DestroyAlgorithmID SECOID_DestroyAlgorithmID_Util
+#define SECOID_FindOID SECOID_FindOID_Util
+#define SECOID_FindOIDByTag SECOID_FindOIDByTag_Util
+#define SECOID_FindOIDTag SECOID_FindOIDTag_Util
+#define SECOID_FindOIDTagDescription SECOID_FindOIDTagDescription_Util
+#define SECOID_GetAlgorithmTag SECOID_GetAlgorithmTag_Util
+#define SECOID_SetAlgorithmID SECOID_SetAlgorithmID_Util
+#define SGN_CompareDigestInfo SGN_CompareDigestInfo_Util
+#define SGN_CopyDigestInfo SGN_CopyDigestInfo_Util
+#define SGN_CreateDigestInfo SGN_CreateDigestInfo_Util
+#define SGN_DestroyDigestInfo SGN_DestroyDigestInfo_Util
+
+/* templates moved from libnss3 */
+#define NSS_Get_SEC_AnyTemplate NSS_Get_SEC_AnyTemplate_Util
+#define NSS_Get_SEC_BitStringTemplate NSS_Get_SEC_BitStringTemplate_Util
+#define NSS_Get_SEC_BMPStringTemplate NSS_Get_SEC_BMPStringTemplate_Util
+#define NSS_Get_SEC_BooleanTemplate NSS_Get_SEC_BooleanTemplate_Util
+#define NSS_Get_SEC_GeneralizedTimeTemplate NSS_Get_SEC_GeneralizedTimeTemplate_Util
+#define NSS_Get_SEC_IA5StringTemplate NSS_Get_SEC_IA5StringTemplate_Util
+#define NSS_Get_SEC_IntegerTemplate NSS_Get_SEC_IntegerTemplate_Util
+#define NSS_Get_SEC_NullTemplate NSS_Get_SEC_NullTemplate_Util
+#define NSS_Get_SEC_ObjectIDTemplate NSS_Get_SEC_ObjectIDTemplate_Util
+#define NSS_Get_SEC_OctetStringTemplate NSS_Get_SEC_OctetStringTemplate_Util
+#define NSS_Get_SEC_PointerToAnyTemplate NSS_Get_SEC_PointerToAnyTemplate_Util
+#define NSS_Get_SEC_PointerToOctetStringTemplate NSS_Get_SEC_PointerToOctetStringTemplate_Util
+#define NSS_Get_SEC_SetOfAnyTemplate NSS_Get_SEC_SetOfAnyTemplate_Util
+#define NSS_Get_SEC_UTCTimeTemplate NSS_Get_SEC_UTCTimeTemplate_Util
+#define NSS_Get_SEC_UTF8StringTemplate NSS_Get_SEC_UTF8StringTemplate_Util
+#define NSS_Get_SECOID_AlgorithmIDTemplate NSS_Get_SECOID_AlgorithmIDTemplate_Util
+#define NSS_Get_sgn_DigestInfoTemplate NSS_Get_sgn_DigestInfoTemplate_Util
+#define SEC_AnyTemplate SEC_AnyTemplate_Util
+#define SEC_BitStringTemplate SEC_BitStringTemplate_Util
+#define SEC_BMPStringTemplate SEC_BMPStringTemplate_Util
+#define SEC_BooleanTemplate SEC_BooleanTemplate_Util
+#define SEC_GeneralizedTimeTemplate SEC_GeneralizedTimeTemplate_Util
+#define SEC_IA5StringTemplate SEC_IA5StringTemplate_Util
+#define SEC_IntegerTemplate SEC_IntegerTemplate_Util
+#define SEC_NullTemplate SEC_NullTemplate_Util
+#define SEC_ObjectIDTemplate SEC_ObjectIDTemplate_Util
+#define SEC_OctetStringTemplate SEC_OctetStringTemplate_Util
+#define SEC_PointerToAnyTemplate SEC_PointerToAnyTemplate_Util
+#define SEC_PointerToOctetStringTemplate SEC_PointerToOctetStringTemplate_Util
+#define SEC_SetOfAnyTemplate SEC_SetOfAnyTemplate_Util
+#define SEC_UTCTimeTemplate SEC_UTCTimeTemplate_Util
+#define SEC_UTF8StringTemplate SEC_UTF8StringTemplate_Util
+#define SECOID_AlgorithmIDTemplate SECOID_AlgorithmIDTemplate_Util
+#define sgn_DigestInfoTemplate sgn_DigestInfoTemplate_Util
+
+#endif /* USE_UTIL_DIRECTLY */
+
+#endif /* _LIBUTIL_H_ */
diff --git a/security/nss/lib/util/watcomfx.h b/security/nss/lib/util/watcomfx.h
new file mode 100644
index 000000000..d0b6fc5d3
--- /dev/null
+++ b/security/nss/lib/util/watcomfx.h
@@ -0,0 +1,62 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is the Netscape security libraries.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1994-2000
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#if defined(__WATCOMC__) || defined(__WATCOM_CPLUSPLUS__)
+#ifndef __WATCOM_FIX_H__
+#define __WATCOM_FIX_H__ 1
+/*
+ * WATCOM's C compiler doesn't default to "__cdecl" conventions for external
+ * symbols and functions. Rather than adding an explicit __cdecl modifier to
+ * every external symbol and function declaration and definition, we use the
+ * following pragma to (attempt to) change WATCOM c's default to __cdecl.
+ * These pragmas were taken from pages 180-181, 266 & 269 of the
+ * Watcom C/C++ version 11 User's Guide, 3rd edition.
+ */
+#if defined(XP_WIN16) || defined(WIN16)
+#pragma aux default "_*" \
+ parm caller [] \
+ value struct float struct routine [ax] \
+ modify [ax bx cx dx es]
+#else
+#pragma aux default "_*" \
+ parm caller [] \
+ value struct float struct routine [eax] \
+ modify [eax ecx edx]
+#endif
+#pragma aux default far
+
+#endif /* once */
+#endif /* WATCOM compiler */