diff options
Diffstat (limited to 'security/nss/lib/util')
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 */ |