diff options
Diffstat (limited to 'security/nss/lib/util')
55 files changed, 18556 insertions, 0 deletions
diff --git a/security/nss/lib/util/Makefile b/security/nss/lib/util/Makefile new file mode 100644 index 000000000..35c2bfb28 --- /dev/null +++ b/security/nss/lib/util/Makefile @@ -0,0 +1,86 @@ +#! gmake +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Netscape security libraries. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1994-2000 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the +# terms of the GNU General Public License Version 2 or later (the +# "GPL"), in which case the provisions of the GPL are applicable +# instead of those above. If you wish to allow use of your +# version of this file only under the terms of the GPL and not to +# allow others to use your version of this file under the MPL, +# indicate your decision by deleting the provisions above and +# replace them with the notice and other provisions required by +# the GPL. If you do not delete the provisions above, a recipient +# may use your version of this file under either the MPL or the +# GPL. +# + +####################################################################### +# (1) Include initial platform-independent assignments (MANDATORY). # +####################################################################### + +include manifest.mn + +####################################################################### +# (2) Include "global" configuration information. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/arch.mk + +ifeq ($(OS_ARCH),HP-UX) + ASFILES += ret_cr16.s +endif + +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). # +####################################################################### + + +tests:: $(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..92dc54d7c --- /dev/null +++ b/security/nss/lib/util/base64.h @@ -0,0 +1,71 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * 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 "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..fd2f3bd0f --- /dev/null +++ b/security/nss/lib/util/ciferfam.h @@ -0,0 +1,87 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * ciferfam.h - cipher familie IDs used for configuring ciphers for export + * control + * + * $Id$ + */ + +#ifndef _CIFERFAM_H_ +#define _CIFERFAM_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 0033, 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_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..a73a1086e --- /dev/null +++ b/security/nss/lib/util/config.mk @@ -0,0 +1,44 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Netscape security libraries. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1994-2000 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the +# terms of the GNU General Public License Version 2 or later (the +# "GPL"), in which case the provisions of the GPL are applicable +# instead of those above. If you wish to allow use of your +# version of this file only under the terms of the GPL and not to +# allow others to use your version of this file under the MPL, +# indicate your decision by deleting the provisions above and +# replace them with the notice and other provisions required by +# the GPL. If you do not delete the provisions above, a recipient +# may use your version of this file under either the MPL or the +# GPL. +# + +# +# Override TARGETS variable so that only static libraries +# are specifed as dependencies within rules.mk. +# + +TARGETS = $(LIBRARY) +SHARED_LIBRARY = +IMPORT_LIBRARY = +PURE_LIBRARY = +PROGRAM = + diff --git a/security/nss/lib/util/derdec.c b/security/nss/lib/util/derdec.c new file mode 100644 index 000000000..914701e33 --- /dev/null +++ b/security/nss/lib/util/derdec.c @@ -0,0 +1,552 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "secder.h" +#include "secerr.h" + +static uint32 +der_indefinite_length(unsigned char *buf, unsigned char *end) +{ + uint32 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, uint32 *contents_len_p) +{ + unsigned char *bp; + unsigned char whole_tag; + uint32 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; +} + +static unsigned char * +der_decode(PRArenaPool *arena, void *dest, DERTemplate *dtemplate, + unsigned char *buf, int header_len, uint32 contents_len) +{ + unsigned char *orig_buf, *end; + unsigned long encode_kind, under_kind; + PRBool explicit, optional, universal, check_tag; + SECItem *item; + SECStatus rv; + PRBool indefinite_length, explicit_indefinite_length; + + 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 (header_len == 0) { + if (optional || (encode_kind & DER_ANY)) + return buf; + PORT_SetError(SEC_ERROR_BAD_DER); + return NULL; + } + + if (encode_kind & DER_POINTER) { + void *place, **placep; + int offset; + + if (dtemplate->sub != NULL) { + dtemplate = dtemplate->sub; + under_kind = dtemplate->kind; + if (universal) { + encode_kind = under_kind; + } + place = PORT_ArenaZAlloc(arena, dtemplate->arg); + offset = dtemplate->offset; + } else { + if (universal) { + under_kind = encode_kind & ~DER_POINTER; + } else { + under_kind = dtemplate->arg; + } + place = PORT_ArenaZAlloc(arena, sizeof(SECItem)); + offset = 0; + } + if (place == NULL) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return NULL; /* Out of memory */ + } + placep = (void **)dest; + *placep = place; + dest = (void *)((char *)place + offset); + } else if (encode_kind & DER_INLINE) { + PORT_Assert (dtemplate->sub != NULL); + dtemplate = dtemplate->sub; + under_kind = dtemplate->kind; + if (universal) { + encode_kind = under_kind; + } + dest = (void *)((char *)dest + dtemplate->offset); + } else if (universal) { + under_kind = encode_kind; + } else { + under_kind = dtemplate->arg; + } + + orig_buf = buf; + end = buf + header_len + contents_len; + + explicit_indefinite_length = PR_FALSE; + + if (explicit) { + /* + * This tag is expected to match exactly. + * (The template has all of the bits specified.) + */ + if (*buf != (encode_kind & DER_TAG_MASK)) { + if (optional) + return buf; + PORT_SetError(SEC_ERROR_BAD_DER); + return NULL; + } + if ((header_len == 2) && (*(buf + 1) == 0x80)) + explicit_indefinite_length = PR_TRUE; + buf += header_len; + rv = der_capture (buf, end, &header_len, &contents_len); + if (rv != SECSuccess) + return NULL; + if (header_len == 0) { /* XXX is this right? */ + PORT_SetError(SEC_ERROR_BAD_DER); + return NULL; + } + optional = PR_FALSE; /* can no longer be optional */ + encode_kind = under_kind; + } + + check_tag = PR_TRUE; + if (encode_kind & (DER_DERPTR | DER_ANY | DER_FORCE | DER_SKIP)) { + PORT_Assert ((encode_kind & DER_ANY) || !optional); + encode_kind = encode_kind & (~DER_FORCE); + under_kind = under_kind & (~DER_FORCE); + check_tag = PR_FALSE; + } + + if (check_tag) { + PRBool wrong; + unsigned char expect_tag, expect_num; + + /* + * This tag is expected to match, but the simple types + * may or may not have the constructed bit set, so we + * have to have all this extra logic. + */ + wrong = PR_TRUE; + expect_tag = encode_kind & DER_TAG_MASK; + expect_num = expect_tag & DER_TAGNUM_MASK; + if (expect_num == DER_SET || expect_num == DER_SEQUENCE) { + if (*buf == (expect_tag | DER_CONSTRUCTED)) + wrong = PR_FALSE; + } else { + if (*buf == expect_tag) + wrong = PR_FALSE; + else if (*buf == (expect_tag | DER_CONSTRUCTED)) + wrong = PR_FALSE; + } + if (wrong) { + if (optional) + return buf; + PORT_SetError(SEC_ERROR_BAD_DER); + return NULL; + } + } + + if (under_kind & DER_DERPTR) { + item = (SECItem *)dest; + if (under_kind & DER_OUTER) { + item->data = buf; + item->len = header_len + contents_len; + } else { + item->data = buf + header_len; + item->len = contents_len; + } + return orig_buf; + } + + if (encode_kind & DER_ANY) { + contents_len += header_len; + header_len = 0; + } + + if ((header_len == 2) && (*(buf + 1) == 0x80)) + indefinite_length = PR_TRUE; + else + indefinite_length = PR_FALSE; + + buf += header_len; + + if (contents_len == 0) + return buf; + + under_kind &= ~DER_OPTIONAL; + + if (under_kind & DER_INDEFINITE) { + int count, thing_size; + unsigned char *sub_buf; + DERTemplate *tmpt; + void *things, **indp, ***placep; + + under_kind &= ~DER_INDEFINITE; + + /* + * Count items. + */ + count = 0; + sub_buf = buf; + while (sub_buf < end) { + if (indefinite_length && sub_buf[0] == 0 && sub_buf[1] == 0) { + break; + } + rv = der_capture (sub_buf, end, &header_len, &contents_len); + if (rv != SECSuccess) + return NULL; + count++; + sub_buf += header_len + contents_len; + } + + /* + * Allocate an array of pointers to items; extra one is for a NULL. + */ + indp = (void**)PORT_ArenaZAlloc(arena, (count + 1) * sizeof(void *)); + if (indp == NULL) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return NULL; + } + + /* + * Prepare. + */ + if (under_kind == DER_SET || under_kind == DER_SEQUENCE) { + tmpt = dtemplate->sub; + PORT_Assert (tmpt != NULL); + thing_size = tmpt->arg; + PORT_Assert (thing_size != 0); + } else { + tmpt = NULL; + thing_size = sizeof(SECItem); + } + + /* + * Allocate the items themselves. + */ + things = PORT_ArenaZAlloc(arena, count * thing_size); + if (things == NULL) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return NULL; + } + + placep = (void ***)dest; + *placep = indp; + + while (count) { + /* ignore return value because we already did whole thing above */ + (void) der_capture (buf, end, &header_len, &contents_len); + if (tmpt != NULL) { + void *sub_thing; + + sub_thing = (void *)((char *)things + tmpt->offset); + buf = der_decode (arena, sub_thing, tmpt, + buf, header_len, contents_len); + if (buf == NULL) + return NULL; + } else { + item = (SECItem *)things; + if (under_kind == DER_ANY) { + contents_len += header_len; + header_len = 0; + } + buf += header_len; + if (under_kind == DER_BIT_STRING) { + item->data = buf + 1; + item->len = ((contents_len - 1) << 3) - *buf; + } else { + item->data = buf; + item->len = contents_len; + } + buf += contents_len; + } + *indp++ = things; + things = (void *)((char *)things + thing_size); + count--; + } + + *indp = NULL; + + goto der_decode_done; + } + + switch (under_kind) { + case DER_SEQUENCE: + case DER_SET: + { + DERTemplate *tmpt; + void *sub_dest; + + for (tmpt = dtemplate + 1; tmpt->kind; tmpt++) { + sub_dest = (void *)((char *)dest + tmpt->offset); + rv = der_capture (buf, end, &header_len, &contents_len); + if (rv != SECSuccess) + return NULL; + buf = der_decode (arena, sub_dest, tmpt, + buf, header_len, contents_len); + if (buf == NULL) + return NULL; + } + } + break; + + case DER_BIT_STRING: + item = (SECItem *)dest; + item->data = buf + 1; + item->len = ((contents_len - 1) << 3) - *buf; + buf += contents_len; + break; + + case DER_SKIP: + buf += contents_len; + break; + + default: + item = (SECItem *)dest; + item->data = buf; + item->len = contents_len; + buf += contents_len; + break; + } + +der_decode_done: + + if (indefinite_length && buf[0] == 0 && buf[1] == 0) { + buf += 2; + } + + if (explicit_indefinite_length && buf[0] == 0 && buf[1] == 0) { + buf += 2; + } + + return buf; +} + +SECStatus +DER_Decode(PRArenaPool *arena, void *dest, DERTemplate *dtemplate, SECItem *src) +{ + unsigned char *buf; + uint32 buf_len, contents_len; + int header_len; + SECStatus rv; + + buf = src->data; + buf_len = src->len; + + rv = der_capture (buf, buf + buf_len, &header_len, &contents_len); + if (rv != SECSuccess) + return rv; + + dest = (void *)((char *)dest + dtemplate->offset); + buf = der_decode (arena, dest, dtemplate, buf, header_len, contents_len); + if (buf == NULL) + return SECFailure; + + return SECSuccess; +} + +SECStatus +DER_Lengths(SECItem *item, int *header_len_p, uint32 *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..191b00528 --- /dev/null +++ b/security/nss/lib/util/derenc.c @@ -0,0 +1,504 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "secder.h" +#include "secerr.h" +/* + * 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) } +}; + + +static int +header_length(DERTemplate *dtemplate, uint32 contents_len) +{ + uint32 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) { + 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 uint32 +contents_length(DERTemplate *dtemplate, void *src) +{ + uint32 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) { + uint32 sub_len; + void **indp; + + 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; + void *sub_src; + + tmpt = dtemplate->sub; + + for (; *indp != NULL; indp++) { + 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; + 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; + uint32 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; + uint32 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; + void *sub_src; + + tmpt = dtemplate->sub; + for (; *indp != NULL; indp++) { + 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..555d5aff7 --- /dev/null +++ b/security/nss/lib/util/dersubr.c @@ -0,0 +1,258 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "secder.h" +#include <limits.h> +#include "secerr.h" + +int +DER_LengthLength(uint32 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, uint32 len) +{ + unsigned char b[4]; + + b[0] = (len >> 24) & 0xff; + b[1] = (len >> 16) & 0xff; + b[2] = (len >> 8) & 0xff; + b[3] = len & 0xff; + 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 an int32. + */ +SECStatus +DER_SetInteger(PRArenaPool *arena, SECItem *it, int32 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 uint32. + */ +SECStatus +DER_SetUInteger(PRArenaPool *arena, SECItem *it, uint32 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 = 0xffL << ((sizeof(ival) - 1)*8); + + while (len) { + if (ival & overflow) { + 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 = 0xffL << ((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..5fbdca656 --- /dev/null +++ b/security/nss/lib/util/dertime.c @@ -0,0 +1,334 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#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 C_SINGLE_QUOTE '\047' + +#define DIGITHI(dig) (((dig) - '0') * 10) +#define DIGITLO(dig) ((dig) - '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'); \ +} + +#define SECMIN ((time_t) 60L) +#define SECHOUR (60L*SECMIN) +#define SECDAY (24L*SECHOUR) +#define SECYEAR (365L*SECDAY) + +static long monthToDayInYear[12] = { + 0, + 31, + 31+28, + 31+28+31, + 31+28+31+30, + 31+28+31+30+31, + 31+28+31+30+31+30, + 31+28+31+30+31+30+31, + 31+28+31+30+31+30+31+31, + 31+28+31+30+31+30+31+31+30, + 31+28+31+30+31+30+31+31+30+31, + 31+28+31+30+31+30+31+31+30+31+30, +}; + +/* gmttime must contains UTC time in micro-seconds unit */ +SECStatus +DER_TimeToUTCTime(SECItem *dst, int64 gmttime) +{ + PRExplodedTime printableTime; + unsigned char *d; + + dst->len = 13; + dst->data = d = (unsigned char*) PORT_Alloc(13); + 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++; + + /* UTC time does not handle the years before 1950 */ + if (printableTime.tm_year < 1950) + return SECFailure; + + /* 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_AsciiToTime(int64 *dst, char *string) +{ + long year, month, mday, hour, minute, second, hourOff, minOff, days; + int64 result, tmp1, tmp2; + + /* Verify time is formatted properly and capture information */ + second = 0; + hourOff = 0; + minOff = 0; + CAPTURE(year,string+0,loser); + if (year < 50) { + /* ASSUME that year # is in the 2000's, not the 1900's */ + year += 100; + } + CAPTURE(month,string+2,loser); + if ((month == 0) || (month > 12)) goto loser; + CAPTURE(mday,string+4,loser); + if ((mday == 0) || (mday > 31)) goto loser; + CAPTURE(hour,string+6,loser); + if (hour > 23) goto loser; + CAPTURE(minute,string+8,loser); + if (minute > 59) goto loser; + if (ISDIGIT(string[10])) { + CAPTURE(second,string+10,loser); + if (second > 59) goto loser; + string += 2; + } + if (string[10] == '+') { + CAPTURE(hourOff,string+11,loser); + if (hourOff > 23) goto loser; + CAPTURE(minOff,string+13,loser); + if (minOff > 59) goto loser; + } else if (string[10] == '-') { + CAPTURE(hourOff,string+11,loser); + if (hourOff > 23) goto loser; + hourOff = -hourOff; + CAPTURE(minOff,string+13,loser); + if (minOff > 59) goto loser; + minOff = -minOff; + } else if (string[10] != 'Z') { + goto loser; + } + + + /* Convert pieces back into a single value year */ + LL_I2L(tmp1, (year-70L)); + LL_I2L(tmp2, SECYEAR); + LL_MUL(result, tmp1, tmp2); + + LL_I2L(tmp1, ( (mday-1L)*SECDAY + hour*SECHOUR + minute*SECMIN - + hourOff*SECHOUR - minOff*SECMIN + second ) ); + LL_ADD(result, result, tmp1); + + /* + ** Have to specially handle the day in the month and the year, to + ** take into account leap days. The return time value is in + ** seconds since January 1st, 12:00am 1970, so start examining + ** the time after that. We can't represent a time before that. + */ + + /* Using two digit years, we can only represent dates from 1970 + to 2069. As a result, we cannot run into the leap year rule + that states that 1700, 2100, etc. are not leap years (but 2000 + is). In other words, there are no years in the span of time + that we can represent that are == 0 mod 4 but are not leap + years. Whew. + */ + + days = monthToDayInYear[month-1]; + days += (year - 68)/4; + + if (((year % 4) == 0) && (month < 3)) { + days--; + } + + LL_I2L(tmp1, (days * SECDAY) ); + LL_ADD(result, result, tmp1 ); + + /* convert to micro seconds */ + LL_I2L(tmp1, PR_USEC_PER_SEC); + LL_MUL(result, result, tmp1); + + *dst = result; + return SECSuccess; + + loser: + PORT_SetError(SEC_ERROR_INVALID_TIME); + return SECFailure; + +} + +SECStatus +DER_UTCTimeToTime(int64 *dst, SECItem *time) +{ + return DER_AsciiToTime(dst, (char*) time->data); +} + +/* + 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_TimeToGeneralizedTime(SECItem *dst, int64 gmttime) +{ + PRExplodedTime printableTime; + unsigned char *d; + + dst->len = 15; + dst->data = d = (unsigned char*) PORT_Alloc(15); + if (!d) { + return SECFailure; + } + + /*Convert a int64 time to a printable format. This is a temporary call + until we change to NSPR 2.0 + */ + 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; +} + +/* + The caller should make sure that the generalized time should only + be used for the certificate validity after the year 2051; otherwise, + the certificate should be consider invalid!? + */ +SECStatus +DER_GeneralizedTimeToTime(int64 *dst, SECItem *time) +{ + PRExplodedTime genTime; + char *string; + long hourOff, minOff; + uint16 century; + + string = (char *)time->data; + PORT_Memset (&genTime, 0, sizeof (genTime)); + + /* Verify time is formatted properly and capture information */ + hourOff = 0; + minOff = 0; + + CAPTURE(century, string+0, loser); + century *= 100; + CAPTURE(genTime.tm_year,string+2,loser); + genTime.tm_year += century; + + CAPTURE(genTime.tm_month,string+4,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+6,loser); + if ((genTime.tm_mday == 0) || (genTime.tm_mday > 31)) goto loser; + + CAPTURE(genTime.tm_hour,string+8,loser); + if (genTime.tm_hour > 23) goto loser; + + CAPTURE(genTime.tm_min,string+10,loser); + if (genTime.tm_min > 59) goto loser; + + if (ISDIGIT(string[12])) { + CAPTURE(genTime.tm_sec,string+12,loser); + if (genTime.tm_sec > 59) goto loser; + string += 2; + } + if (string[12] == '+') { + CAPTURE(hourOff,string+13,loser); + if (hourOff > 23) goto loser; + CAPTURE(minOff,string+15,loser); + if (minOff > 59) goto loser; + } else if (string[12] == '-') { + CAPTURE(hourOff,string+13,loser); + if (hourOff > 23) goto loser; + hourOff = -hourOff; + CAPTURE(minOff,string+15,loser); + if (minOff > 59) goto loser; + minOff = -minOff; + } else if (string[12] != 'Z') { + goto loser; + } + + /* Since the values of hourOff and minOff are small, there will + be no loss of data by the conversion to int8 */ + /* Convert the GMT offset to seconds and save it it genTime + for the implode time process */ + 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/mac_rand.c b/security/nss/lib/util/mac_rand.c new file mode 100644 index 000000000..c8596a9f0 --- /dev/null +++ b/security/nss/lib/util/mac_rand.c @@ -0,0 +1,280 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef notdef +#include "xp_core.h" +#include "xp_file.h" +#endif +#include "secrng.h" +#include "mcom_db.h" +#ifdef XP_MAC +#include <Events.h> +#include <OSUtils.h> +#include <QDOffscreen.h> +#include <PPCToolbox.h> +#include <Processes.h> +#include <LowMem.h> + +/* Static prototypes */ +static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen); +void FE_ReadScreen(); + +static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen) +{ + union endianness { + int32 i; + char c[4]; + } u; + + if (srclen <= dstlen) { + memcpy(dst, src, srclen); + return srclen; + } + u.i = 0x01020304; + if (u.c[0] == 0x01) { + /* big-endian case */ + memcpy(dst, (char*)src + (srclen - dstlen), dstlen); + } else { + /* little-endian case */ + memcpy(dst, src, dstlen); + } + return dstlen; +} + +size_t RNG_GetNoise(void *buf, size_t maxbytes) +{ + uint32 c = TickCount(); + return CopyLowBits(buf, maxbytes, &c, sizeof(c)); +} + +void RNG_FileForRNG(char *filename) +{ + unsigned char buffer[BUFSIZ]; + size_t bytes; +#ifdef notdef /*sigh*/ + XP_File file; + unsigned long totalFileBytes = 0; + + if (filename == NULL) /* For now, read in global history if filename is null */ + file = XP_FileOpen(NULL, xpGlobalHistory,XP_FILE_READ_BIN); + else + file = XP_FileOpen(NULL, xpURL,XP_FILE_READ_BIN); + if (file != NULL) { + for (;;) { + bytes = XP_FileRead(buffer, sizeof(buffer), file); + if (bytes == 0) break; + RNG_RandomUpdate( buffer, bytes); + totalFileBytes += bytes; + if (totalFileBytes > 100*1024) break; /* No more than 100 K */ + } + XP_FileClose(file); + } +#endif + /* + * Pass yet another snapshot of our highest resolution clock into + * the hash function. + */ + bytes = RNG_GetNoise(buffer, sizeof(buffer)); + RNG_RandomUpdate(buffer, sizeof(buffer)); +} + +void RNG_SystemInfoForRNG() +{ +/* Time */ + { + unsigned long sec; + size_t bytes; + GetDateTime(&sec); /* Current time since 1970 */ + RNG_RandomUpdate( &sec, sizeof(sec)); + bytes = RNG_GetNoise(&sec, sizeof(sec)); + RNG_RandomUpdate(&sec, bytes); + } +/* User specific variables */ + { + MachineLocation loc; + ReadLocation(&loc); + RNG_RandomUpdate( &loc, sizeof(loc)); + } +/* User name */ + { + unsigned long userRef; + Str32 userName; + GetDefaultUser(&userRef, userName); + RNG_RandomUpdate( &userRef, sizeof(userRef)); + RNG_RandomUpdate( userName, sizeof(userName)); + } +/* Mouse location */ + { + Point mouseLoc; + GetMouse(&mouseLoc); + RNG_RandomUpdate( &mouseLoc, sizeof(mouseLoc)); + } +/* Keyboard time threshold */ + { + SInt16 keyTresh = LMGetKeyThresh(); + RNG_RandomUpdate( &keyTresh, sizeof(keyTresh)); + } +/* Last key pressed */ + { + SInt8 keyLast; + keyLast = LMGetKbdLast(); + RNG_RandomUpdate( &keyLast, sizeof(keyLast)); + } +/* Volume */ + { + UInt8 volume = LMGetSdVolume(); + RNG_RandomUpdate( &volume, sizeof(volume)); + } +/* Current directory */ + { + SInt32 dir = LMGetCurDirStore(); + RNG_RandomUpdate( &dir, sizeof(dir)); + } +/* Process information about all the processes in the machine */ + { + ProcessSerialNumber process; + ProcessInfoRec pi; + + process.highLongOfPSN = process.lowLongOfPSN = kNoProcess; + + while (GetNextProcess(&process) == noErr) + { + FSSpec fileSpec; + pi.processInfoLength = sizeof(ProcessInfoRec); + pi.processName = NULL; + pi.processAppSpec = &fileSpec; + GetProcessInformation(&process, &pi); + RNG_RandomUpdate( &pi, sizeof(pi)); + RNG_RandomUpdate( &fileSpec, sizeof(fileSpec)); + } + } + +/* Heap */ + { + THz zone = LMGetTheZone(); + RNG_RandomUpdate( &zone, sizeof(zone)); + } + +/* Screen */ + { + GDHandle h = LMGetMainDevice(); /* GDHandle is **GDevice */ + RNG_RandomUpdate( *h, sizeof(GDevice)); + } +/* Scrap size */ + { + SInt32 scrapSize = LMGetScrapSize(); + RNG_RandomUpdate( &scrapSize, sizeof(scrapSize)); + } +/* Scrap count */ + { + SInt16 scrapCount = LMGetScrapCount(); + RNG_RandomUpdate( &scrapCount, sizeof(scrapCount)); + } +/* File stuff, last modified, etc. */ + { + HParamBlockRec pb; + GetVolParmsInfoBuffer volInfo; + pb.ioParam.ioVRefNum = 0; + pb.ioParam.ioNamePtr = nil; + pb.ioParam.ioBuffer = (Ptr) &volInfo; + pb.ioParam.ioReqCount = sizeof(volInfo); + PBHGetVolParmsSync(&pb); + RNG_RandomUpdate( &volInfo, sizeof(volInfo)); + } +/* Event queue */ + { + EvQElPtr eventQ; + for (eventQ = (EvQElPtr) LMGetEventQueue()->qHead; + eventQ; + eventQ = (EvQElPtr)eventQ->qLink) + RNG_RandomUpdate( &eventQ->evtQWhat, sizeof(EventRecord)); + } + FE_ReadScreen(); + RNG_FileForRNG(NULL); +} + +void FE_ReadScreen() +{ + UInt16 coords[4]; + PixMapHandle pmap; + GDHandle gh; + UInt16 screenHeight; + UInt16 screenWidth; /* just what they say */ + UInt32 bytesToRead; /* number of bytes we're giving */ + UInt32 offset; /* offset into the graphics buffer */ + UInt16 rowBytes; + UInt32 rowsToRead; + float bytesPerPixel; /* dependent on buffer depth */ + Ptr p; /* temporary */ + UInt16 x, y, w, h; + + gh = LMGetMainDevice(); + if ( !gh ) + return; + pmap = (**gh).gdPMap; + if ( !pmap ) + return; + + RNG_GenerateGlobalRandomBytes( coords, sizeof( coords ) ); + + /* make x and y inside the screen rect */ + screenHeight = (**pmap).bounds.bottom - (**pmap).bounds.top; + screenWidth = (**pmap).bounds.right - (**pmap).bounds.left; + x = coords[0] % screenWidth; + y = coords[1] % screenHeight; + w = ( coords[2] & 0x7F ) | 0x40; /* Make sure that w is in the range 64..128 */ + h = ( coords[3] & 0x7F ) | 0x40; /* same for h */ + + bytesPerPixel = (**pmap).pixelSize / 8; + rowBytes = (**pmap).rowBytes & 0x7FFF; + + /* starting address */ + offset = ( rowBytes * y ) + (UInt32)( (float)x * bytesPerPixel ); + + /* don't read past the end of the pixmap's rowbytes */ + bytesToRead = MIN( (UInt32)( w * bytesPerPixel ), + (UInt32)( rowBytes - ( x * bytesPerPixel ) ) ); + + /* don't read past the end of the graphics device pixmap */ + rowsToRead = MIN( h, + ( screenHeight - y ) ); + + p = GetPixBaseAddr( pmap ) + offset; + + while ( rowsToRead-- ) + { + RNG_RandomUpdate( p, bytesToRead ); + p += rowBytes; + } +} +#endif diff --git a/security/nss/lib/util/manifest.mn b/security/nss/lib/util/manifest.mn new file mode 100644 index 000000000..e88b0f003 --- /dev/null +++ b/security/nss/lib/util/manifest.mn @@ -0,0 +1,99 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under the License. +# +# The Original Code is the Netscape security libraries. +# +# The Initial Developer of the Original Code is Netscape +# Communications Corporation. Portions created by Netscape are +# Copyright (C) 1994-2000 Netscape Communications Corporation. All +# Rights Reserved. +# +# Contributor(s): +# +# Alternatively, the contents of this file may be used under the +# terms of the GNU General Public License Version 2 or later (the +# "GPL"), in which case the provisions of the GPL are applicable +# instead of those above. If you wish to allow use of your +# version of this file only under the terms of the GPL and not to +# allow others to use your version of this file under the MPL, +# indicate your decision by deleting the provisions above and +# replace them with the notice and other provisions required by +# the GPL. If you do not delete the provisions above, a recipient +# may use your version of this file under either the MPL or the +# GPL. +# +CORE_DEPTH = ../../.. + +EXPORTS = \ + base64.h \ + ciferfam.h \ + nssb64.h \ + nssb64t.h \ + nsslocks.h \ + nssrwlk.h \ + nssrwlkt.h \ + portreg.h \ + pqgutil.h \ + secasn1.h \ + secasn1t.h \ + seccomon.h \ + secder.h \ + secdert.h \ + secdig.h \ + secdigt.h \ + secitem.h \ + secoid.h \ + secoidt.h \ + secport.h \ + secrng.h \ + secrngt.h \ + secerr.h \ + watcomfx.h \ + $(NULL) + +MODULE = security + +CSRCS = \ + secdig.c \ + derdec.c \ + derenc.c \ + dersubr.c \ + dertime.c \ + nssb64d.c \ + nssrwlk.c \ + nsslocks.c \ + portreg.c \ + pqgutil.c \ + secalgid.c \ + secasn1d.c \ + secasn1e.c \ + secasn1u.c \ + secitem.c \ + secoid.c \ + sectime.c \ + secport.c \ + secinit.c \ + sysrand.c \ + utf8.c \ + $(NULL) + +ifeq ($(subst /,_,$(shell uname -s)),OS2) + CSRCS += os2_rand.c +endif + +# mac_rand.c +# unix_rand.c +# win_rand.c +# prelib.c + +REQUIRES = security dbm + +LIBRARY_NAME = secutil diff --git a/security/nss/lib/util/nssb64.h b/security/nss/lib/util/nssb64.h new file mode 100644 index 000000000..4430891e4 --- /dev/null +++ b/security/nss/lib/util/nssb64.h @@ -0,0 +1,124 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * Public prototypes for base64 encoding/decoding. + * + * $Id$ + */ +#ifndef _NSSB64_H_ +#define _NSSB64_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 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 (PRArenaPool *arenaOpt, SECItem *outItemOpt, + const char *inStr, unsigned int inLen); + +/* + * Perform base64 decoding 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 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 (PRArenaPool *arenaOpt, char *outStrOpt, + unsigned int maxOutLen, SECItem *binaryItem); + +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..3eaae6c89 --- /dev/null +++ b/security/nss/lib/util/nssb64d.c @@ -0,0 +1,843 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * 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 + * PR_IMPLEMENT 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 not 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 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 (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. +*/ +extern unsigned char * +ATOB_AsciiToData(const char *string, unsigned int *lenp) +{ + SECItem binary_item, *dummy; + + 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. +*/ +extern SECStatus +ATOB_ConvertAsciiToItem(SECItem *binary_item, char *ascii) +{ + SECItem *dummy; + + 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/nssb64t.h b/security/nss/lib/util/nssb64t.h new file mode 100644 index 000000000..b7b079d8c --- /dev/null +++ b/security/nss/lib/util/nssb64t.h @@ -0,0 +1,45 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * Public data structures for base64 encoding/decoding. + * + * $Id$ + */ +#ifndef _NSSB64T_H_ +#define _NSSB64T_H_ + +typedef struct NSSBase64DecoderStr NSSBase64Decoder; +typedef struct NSSBase64EncoderStr NSSBase64Encoder; + +#endif /* _NSSB64T_H_ */ diff --git a/security/nss/lib/util/nsslocks.c b/security/nss/lib/util/nsslocks.c new file mode 100644 index 000000000..c3bb0f0f2 --- /dev/null +++ b/security/nss/lib/util/nsslocks.c @@ -0,0 +1,99 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * nsslocks.h - threadsafe functions to initialize lock pointers. + * + * NOTE - These are not public interfaces + * + * $Id$ + */ + +#include "seccomon.h" +#include "nsslocks.h" +#include "pratom.h" +#include "prthread.h" + +/* Given the address of a (global) pointer to a PRLock, + * atomicly create the lock and initialize the (global) pointer, + * if it is not already created/initialized. + */ + +SECStatus +nss_InitLock( PRLock **ppLock) +{ + static PRInt32 initializers; + + PORT_Assert( ppLock != NULL); + + /* atomically initialize the lock */ + while (!*ppLock) { + PRInt32 myAttempt = PR_AtomicIncrement(&initializers); + if (myAttempt == 1) { + *ppLock = PR_NewLock(); + (void) PR_AtomicDecrement(&initializers); + break; + } + PR_Sleep(PR_INTERVAL_NO_WAIT); /* PR_Yield() */ + (void) PR_AtomicDecrement(&initializers); + } + + return (*ppLock != NULL) ? SECSuccess : SECFailure; +} + +/* Given the address of a (global) pointer to a PRMonitor, + * atomicly create the monitor and initialize the (global) pointer, + * if it is not already created/initialized. + */ + +SECStatus +nss_InitMonitor(PRMonitor **ppMonitor) +{ + static PRInt32 initializers; + + PORT_Assert( ppMonitor != NULL); + + /* atomically initialize the lock */ + while (!*ppMonitor) { + PRInt32 myAttempt = PR_AtomicIncrement(&initializers); + if (myAttempt == 1) { + *ppMonitor = PR_NewMonitor(); + (void) PR_AtomicDecrement(&initializers); + break; + } + PR_Sleep(PR_INTERVAL_NO_WAIT); /* PR_Yield() */ + (void) PR_AtomicDecrement(&initializers); + } + + return (*ppMonitor != NULL) ? SECSuccess : SECFailure; +} diff --git a/security/nss/lib/util/nsslocks.h b/security/nss/lib/util/nsslocks.h new file mode 100644 index 000000000..466a1ab4d --- /dev/null +++ b/security/nss/lib/util/nsslocks.h @@ -0,0 +1,67 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * nsslocks.h - threadsafe functions to initialize lock pointers. + * + * NOTE - These are not public interfaces + * + * $Id$ + */ + +#ifndef _NSSLOCKS_H_ +#define _NSSLOCKS_H_ + +#include "seccomon.h" +#include "prlock.h" +#include "prmon.h" + +SEC_BEGIN_PROTOS + +/* Given the address of a (global) pointer to a PRLock, + * atomicly create the lock and initialize the (global) pointer, + * if it is not already created/initialized. + */ + +extern SECStatus nss_InitLock( PRLock **ppLock); + +/* Given the address of a (global) pointer to a PRMonitor, + * atomicly create the monitor and initialize the (global) pointer, + * if it is not already created/initialized. + */ + +extern SECStatus nss_InitMonitor(PRMonitor **ppMonitor); + +SEC_END_PROTOS + +#endif diff --git a/security/nss/lib/util/nssrwlk.c b/security/nss/lib/util/nssrwlk.c new file mode 100644 index 000000000..0c4ece1ee --- /dev/null +++ b/security/nss/lib/util/nssrwlk.c @@ -0,0 +1,512 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "nssrwlk.h" +#include "nspr.h" + +PR_BEGIN_EXTERN_C + +/* + * Reader-writer lock + */ +struct nssRWLockStr { + PRLock * 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 */ + PRCondVar * rw_reader_waitq; /* cvar for readers */ + PRCondVar * 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 + * + */ + +PR_IMPLEMENT(NSSRWLock *) +NSSRWLock_New(PRUint32 lock_rank, const char *lock_name) +{ + NSSRWLock *rwlock; + + rwlock = PR_NEWZAP(NSSRWLock); + if (rwlock == NULL) + return NULL; + + rwlock->rw_lock = PR_NewLock(); + if (rwlock->rw_lock == NULL) { + goto loser; + } + rwlock->rw_reader_waitq = PR_NewCondVar(rwlock->rw_lock); + if (rwlock->rw_reader_waitq == NULL) { + goto loser; + } + rwlock->rw_writer_waitq = PR_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". +*/ +PR_IMPLEMENT(void) +NSSRWLock_Destroy(NSSRWLock *rwlock) +{ + PR_ASSERT(rwlock != NULL); + PR_ASSERT(rwlock->rw_waiting_readers == 0); + + /* XXX Shouldn't we lock the PRLock before destroying this?? */ + + if (rwlock->rw_name) + PR_Free(rwlock->rw_name); + if (rwlock->rw_reader_waitq) + PR_DestroyCondVar(rwlock->rw_reader_waitq); + if (rwlock->rw_writer_waitq) + PR_DestroyCondVar(rwlock->rw_writer_waitq); + if (rwlock->rw_lock) + PR_DestroyLock(rwlock->rw_lock); + PR_DELETE(rwlock); +} + +/*********************************************************************** +** 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. +** If the lock cannot be created because of resource constraints, +** the pointer will be left NULL. +** +***********************************************************************/ +PR_IMPLEMENT(NSSRWLock *) +nssRWLock_AtomicCreate( NSSRWLock ** prwlock, + PRUint32 lock_rank, + const char * lock_name) +{ + NSSRWLock * rwlock; + static PRInt32 initializers; + + PR_ASSERT(prwlock != NULL); + + /* atomically initialize the lock */ + while (NULL == (rwlock = *prwlock)) { + PRInt32 myAttempt = PR_AtomicIncrement(&initializers); + if (myAttempt == 1) { + *prwlock = rwlock = NSSRWLock_New(lock_rank, lock_name); + (void) PR_AtomicDecrement(&initializers); + break; + } + PR_Sleep(PR_INTERVAL_NO_WAIT); /* PR_Yield() */ + (void) PR_AtomicDecrement(&initializers); + } + + return rwlock; +} + +/* +** Read-lock the RWLock. +*/ +PR_IMPLEMENT(void) +NSSRWLock_LockRead(NSSRWLock *rwlock) +{ + PRThread *me = PR_GetCurrentThread(); + + PR_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++; + PR_WaitCondVar(rwlock->rw_reader_waitq, PR_INTERVAL_NO_TIMEOUT); + rwlock->rw_waiting_readers--; + } + rwlock->rw_reader_locks++; /* Increment read-lock count */ + + PR_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. +*/ +PR_IMPLEMENT(void) +NSSRWLock_UnlockRead(NSSRWLock *rwlock) +{ + PRThread *me = PR_GetCurrentThread(); + + PR_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. */ + + PR_NotifyCondVar(rwlock->rw_writer_waitq); /* wake him up. */ + } + + PR_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. +*/ +PR_IMPLEMENT(void) +NSSRWLock_LockWrite(NSSRWLock *rwlock) +{ + PRInt32 lock_acquired = 0; + PRThread *me = PR_GetCurrentThread(); + + PR_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++; + PR_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 */ + + PR_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. +*/ +PR_IMPLEMENT(void) +NSSRWLock_UnlockWrite(NSSRWLock *rwlock) +{ + PRThread *me = PR_GetCurrentThread(); + + PR_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. */ + + if (rwlock->rw_reader_locks == 0) { /* no readers, wake up somebody. */ + /* Give preference to waiting writers. */ + if (rwlock->rw_waiting_writers > 0) + PR_NotifyCondVar(rwlock->rw_writer_waitq); + else if (rwlock->rw_waiting_readers > 0) + PR_NotifyAllCondVar(rwlock->rw_reader_waitq); + } + } + PR_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. */ +PR_IMPLEMENT(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 + PR_Lock(rwlock->rw_lock); +#endif + ownWriteLock = (PRBool)(me == rwlock->rw_owner); +#if UNNECESSARY + PR_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..3cad4b72d --- /dev/null +++ b/security/nss/lib/util/nssrwlk.h @@ -0,0 +1,160 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* +** 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 "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. +** +***********************************************************************/ +PR_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. +** +***********************************************************************/ +PR_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 +***********************************************************************/ +PR_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 +***********************************************************************/ +PR_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 +***********************************************************************/ +PR_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 +***********************************************************************/ +PR_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 +***********************************************************************/ +PR_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. +***********************************************************************/ + +PR_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..62f53bf4f --- /dev/null +++ b/security/nss/lib/util/nssrwlkt.h @@ -0,0 +1,47 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef nssrwlkt_h___ +#define nssrwlkt_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/os2_rand.c b/security/nss/lib/util/os2_rand.c new file mode 100644 index 000000000..cbe20a205 --- /dev/null +++ b/security/nss/lib/util/os2_rand.c @@ -0,0 +1,232 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#define INCL_DOS +#define INCL_DOSERRORS +#include <os2.h> +#include <secrng.h> +#include <stdlib.h> + +static BOOL clockTickTime(unsigned long *phigh, unsigned long *plow) +{ + APIRET rc = NO_ERROR; + QWORD qword = {0,0}; + + rc = DosTmrQueryTime(&qword); + if (rc != NO_ERROR) + return FALSE; + + *phigh = qword.ulHi; + *plow = qword.ulLo; + + return TRUE; +} + +size_t RNG_GetNoise(void *buf, size_t maxbuf) +{ + unsigned long high = 0; + unsigned long low = 0; + clock_t val = 0; + int n = 0; + int nBytes = 0; + time_t sTime; + + if (maxbuf <= 0) + return 0; + + clockTickTime(&high, &low); + + /* get the maximally changing bits first */ + nBytes = sizeof(low) > maxbuf ? maxbuf : sizeof(low); + memcpy(buf, &low, nBytes); + n += nBytes; + maxbuf -= nBytes; + + if (maxbuf <= 0) + return n; + + nBytes = sizeof(high) > maxbuf ? maxbuf : sizeof(high); + memcpy(((char *)buf) + n, &high, nBytes); + n += nBytes; + maxbuf -= nBytes; + + if (maxbuf <= 0) + return n; + + /* get the number of milliseconds that have elapsed since application started */ + val = clock(); + + nBytes = sizeof(val) > maxbuf ? maxbuf : sizeof(val); + memcpy(((char *)buf) + n, &val, nBytes); + n += nBytes; + maxbuf -= nBytes; + + if (maxbuf <= 0) + return n; + + /* get the time in seconds since midnight Jan 1, 1970 */ + time(&sTime); + nBytes = sizeof(sTime) > maxbuf ? maxbuf : sizeof(sTime); + memcpy(((char *)buf) + n, &sTime, nBytes); + n += nBytes; + + return n; +} + +void RNG_SystemInfoForRNG(void) +{ + unsigned long *plong = 0; + PTIB ptib; + PPIB ppib; + APIRET rc = NO_ERROR; + DATETIME dt; + COUNTRYCODE cc; + COUNTRYINFO ci; + unsigned long actual; + char path[_MAX_PATH]=""; + unsigned long pathlength = sizeof(path); + FSALLOCATE fsallocate; + FILESTATUS3 fstatus; + unsigned long defaultdrive = 0; + unsigned long logicaldrives = 0; + unsigned long counter = 0; + char buffer[20]; + int nBytes = 0; + + nBytes = RNG_GetNoise(buffer, sizeof(buffer)); + RNG_RandomUpdate(buffer, nBytes); + + /* allocate memory and use address and memory */ + plong = (unsigned long *)malloc(sizeof(*plong)); + RNG_RandomUpdate(&plong, sizeof(plong)); + RNG_RandomUpdate(plong, sizeof(*plong)); + free(plong); + + /* process info */ + rc = DosGetInfoBlocks(&ptib, &ppib); + if (rc == NO_ERROR) + { + RNG_RandomUpdate(ptib, sizeof(*ptib)); + RNG_RandomUpdate(ppib, sizeof(*ppib)); + } + + /* time */ + rc = DosGetDateTime(&dt); + if (rc == NO_ERROR) + { + RNG_RandomUpdate(&dt, sizeof(dt)); + } + + /* country */ + rc = DosQueryCtryInfo(sizeof(ci), &cc, &ci, &actual); + if (rc == NO_ERROR) + { + RNG_RandomUpdate(&cc, sizeof(cc)); + RNG_RandomUpdate(&ci, sizeof(ci)); + RNG_RandomUpdate(&actual, sizeof(actual)); + } + + /* current directory */ + rc = DosQueryCurrentDir(0, path, &pathlength); + if (rc == NO_ERROR) + { + RNG_RandomUpdate(path, strlen(path)); + // path info + rc = DosQueryPathInfo(path, FIL_STANDARD, &fstatus, sizeof(fstatus)); + if (rc == NO_ERROR) + { + RNG_RandomUpdate(&fstatus, sizeof(fstatus)); + } + } + + /* file system info */ + rc = DosQueryFSInfo(0, FSIL_ALLOC, &fsallocate, sizeof(fsallocate)); + if (rc == NO_ERROR) + { + RNG_RandomUpdate(&fsallocate, sizeof(fsallocate)); + } + + /* drive info */ + rc = DosQueryCurrentDisk(&defaultdrive, &logicaldrives); + if (rc == NO_ERROR) + { + RNG_RandomUpdate(&defaultdrive, sizeof(defaultdrive)); + RNG_RandomUpdate(&logicaldrives, sizeof(logicaldrives)); + } + + /* system info */ + rc = DosQuerySysInfo(QSV_MS_COUNT, QSV_MS_COUNT, &counter, sizeof(counter)); + if (rc == NO_ERROR) + { + RNG_RandomUpdate(&counter, sizeof(counter)); + } + + /* more noise */ + nBytes = RNG_GetNoise(buffer, sizeof(buffer)); + RNG_RandomUpdate(buffer, nBytes); +} + +void RNG_FileForRNG(char *filename) +{ + struct stat stat_buf; + unsigned char buffer[1024]; + FILE *file = 0; + int nBytes = 0; + static int totalFileBytes = 0; + + if (stat((char *)filename, &stat_buf) < 0) + return; + + RNG_RandomUpdate((unsigned char*)&stat_buf, sizeof(stat_buf)); + + file = fopen((char *)filename, "r"); + if (file != NULL) + { + for (;;) + { + size_t bytes = fread(buffer, 1, sizeof(buffer), file); + + if (bytes == 0) + break; + + RNG_RandomUpdate(buffer, bytes); + totalFileBytes += bytes; + if (totalFileBytes > 250000) + break; + } + fclose(file); + } + + nBytes = RNG_GetNoise(buffer, 20); + RNG_RandomUpdate(buffer, nBytes); +} diff --git a/security/nss/lib/util/portreg.c b/security/nss/lib/util/portreg.c new file mode 100644 index 000000000..79d13d67c --- /dev/null +++ b/security/nss/lib/util/portreg.c @@ -0,0 +1,317 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * 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(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(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(char *str, char *exp, PRBool case_insensitive); + +static int +_handle_union(char *str, 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(char *str, 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)); +} + +int +PORT_RegExpMatch(char *str, 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, PR_FALSE) == MATCH) { + PORT_Free(exp); + return 0; + } + + punt: + PORT_Free(exp); + return 1; +} + + +/* ------------------------------ shexp_cmp ------------------------------- */ + +int +PORT_RegExpSearch(char *str, 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(char *str, 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_TRUE); + } +} + diff --git a/security/nss/lib/util/portreg.h b/security/nss/lib/util/portreg.h new file mode 100644 index 000000000..39a2df9d5 --- /dev/null +++ b/security/nss/lib/util/portreg.h @@ -0,0 +1,92 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * 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 + +/* + * 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(char *exp); + +/* same as above but uses case insensitive search + */ +extern int PORT_RegExpCaseSearch(char *str, char *exp); + +SEC_END_PROTOS + +#endif diff --git a/security/nss/lib/util/pqgutil.c b/security/nss/lib/util/pqgutil.c new file mode 100644 index 000000000..dad8c6b78 --- /dev/null +++ b/security/nss/lib/util/pqgutil.c @@ -0,0 +1,267 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ +#include "pqgutil.h" +#include "prerror.h" +#include "secitem.h" + +#define PQG_DEFAULT_CHUNKSIZE 2048 /* bytes */ + +/************************************************************************** + * Return a pointer to a new PQGParams struct that is a duplicate of * + * the one passed as an argument. * + * Return NULL on failure, or if NULL was passed in. * + * * + **************************************************************************/ + +PQGParams * +PQG_DupParams(const PQGParams *src) +{ + PRArenaPool *arena; + PQGParams *dest; + SECStatus status; + + if (src == NULL) { + PORT_SetError(PR_INVALID_ARGUMENT_ERROR); + return NULL; + } + + arena = PORT_NewArena(PQG_DEFAULT_CHUNKSIZE); + if (arena == NULL) + goto loser; + + dest = (PQGParams*)PORT_ArenaZAlloc(arena, sizeof(PQGParams)); + if (dest == NULL) + goto loser; + + dest->arena = arena; + + status = SECITEM_CopyItem(arena, &dest->prime, &src->prime); + if (status != SECSuccess) + goto loser; + + status = SECITEM_CopyItem(arena, &dest->subPrime, &src->subPrime); + if (status != SECSuccess) + goto loser; + + status = SECITEM_CopyItem(arena, &dest->base, &src->base); + if (status != SECSuccess) + goto loser; + + return dest; + +loser: + if (arena != NULL) + PORT_FreeArena(arena, PR_FALSE); + return NULL; +} + +/************************************************************************** + * Return a pointer to a new PQGParams struct that is constructed from * + * copies of the arguments passed in. * + * Return NULL on failure. * + **************************************************************************/ + +PQGParams * +PQG_NewParams(const SECItem * prime, const SECItem * subPrime, + const SECItem * base) +{ + PQGParams * dest; + PQGParams src; + + src.arena = NULL; + src.prime = *prime; + src.subPrime = *subPrime; + src.base = *base; + dest = PQG_DupParams(&src); + return dest; +} + +/************************************************************************** + * Fills in caller's "prime" SECItem with the prime value in params. + * Contents can be freed by calling SECITEM_FreeItem(prime, PR_FALSE); + **************************************************************************/ +SECStatus +PQG_GetPrimeFromParams(const PQGParams *params, SECItem * prime) +{ + return SECITEM_CopyItem(NULL, prime, ¶ms->prime); +} + +/************************************************************************** + * Fills in caller's "subPrime" SECItem with the prime value in params. + * Contents can be freed by calling SECITEM_FreeItem(subPrime, PR_FALSE); + **************************************************************************/ +SECStatus +PQG_GetSubPrimeFromParams(const PQGParams *params, SECItem * subPrime) +{ + return SECITEM_CopyItem(NULL, subPrime, ¶ms->subPrime); +} + +/************************************************************************** + * Fills in caller's "base" SECItem with the base value in params. + * Contents can be freed by calling SECITEM_FreeItem(base, PR_FALSE); + **************************************************************************/ +SECStatus +PQG_GetBaseFromParams(const PQGParams *params, SECItem * base) +{ + return SECITEM_CopyItem(NULL, base, ¶ms->base); +} + +/************************************************************************** + * Free the PQGParams struct and the things it points to. * + **************************************************************************/ +void +PQG_DestroyParams(PQGParams *params) +{ + if (params == NULL) + return; + if (params->arena != NULL) { + PORT_FreeArena(params->arena, PR_FALSE); /* don't zero it */ + return; + } + SECITEM_FreeItem(¶ms->prime, PR_FALSE); /* don't free prime */ + SECITEM_FreeItem(¶ms->subPrime, PR_FALSE); /* don't free subPrime */ + SECITEM_FreeItem(¶ms->base, PR_FALSE); /* don't free base */ + PORT_Free(params); +} + +/************************************************************************** + * Return a pointer to a new PQGVerify struct that is a duplicate of * + * the one passed as an argument. * + * Return NULL on failure, or if NULL was passed in. * + **************************************************************************/ + +PQGVerify * +PQG_DupVerify(const PQGVerify *src) +{ + PRArenaPool *arena; + PQGVerify * dest; + SECStatus status; + + if (src == NULL) { + PORT_SetError(PR_INVALID_ARGUMENT_ERROR); + return NULL; + } + + arena = PORT_NewArena(PQG_DEFAULT_CHUNKSIZE); + if (arena == NULL) + goto loser; + + dest = (PQGVerify*)PORT_ArenaZAlloc(arena, sizeof(PQGVerify)); + if (dest == NULL) + goto loser; + + dest->arena = arena; + dest->counter = src->counter; + + status = SECITEM_CopyItem(arena, &dest->seed, &src->seed); + if (status != SECSuccess) + goto loser; + + status = SECITEM_CopyItem(arena, &dest->h, &src->h); + if (status != SECSuccess) + goto loser; + + return dest; + +loser: + if (arena != NULL) + PORT_FreeArena(arena, PR_FALSE); + return NULL; +} + +/************************************************************************** + * Return a pointer to a new PQGVerify struct that is constructed from * + * copies of the arguments passed in. * + * Return NULL on failure. * + **************************************************************************/ + +PQGVerify * +PQG_NewVerify(unsigned int counter, const SECItem * seed, const SECItem * h) +{ + PQGVerify * dest; + PQGVerify src; + + src.arena = NULL; + src.counter = counter; + src.seed = *seed; + src.h = *h; + dest = PQG_DupVerify(&src); + return dest; +} + +/************************************************************************** + * Returns the "counter" value from the PQGVerify. + **************************************************************************/ +unsigned int +PQG_GetCounterFromVerify(const PQGVerify *verify) +{ + return verify->counter; +} + +/************************************************************************** + * Fills in caller's "seed" SECItem with the seed value in verify. + * Contents can be freed by calling SECITEM_FreeItem(seed, PR_FALSE); + **************************************************************************/ +SECStatus +PQG_GetSeedFromVerify(const PQGVerify *verify, SECItem * seed) +{ + return SECITEM_CopyItem(NULL, seed, &verify->seed); +} + +/************************************************************************** + * Fills in caller's "h" SECItem with the h value in verify. + * Contents can be freed by calling SECITEM_FreeItem(h, PR_FALSE); + **************************************************************************/ +SECStatus +PQG_GetHFromVerify(const PQGVerify *verify, SECItem * h) +{ + return SECITEM_CopyItem(NULL, h, &verify->h); +} + +/************************************************************************** + * Free the PQGVerify struct and the things it points to. * + **************************************************************************/ + +void +PQG_DestroyVerify(PQGVerify *vfy) +{ + if (vfy == NULL) + return; + if (vfy->arena != NULL) { + PORT_FreeArena(vfy->arena, PR_FALSE); /* don't zero it */ + return; + } + SECITEM_FreeItem(&vfy->seed, PR_FALSE); /* don't free seed */ + SECITEM_FreeItem(&vfy->h, PR_FALSE); /* don't free h */ + PORT_Free(vfy); +} diff --git a/security/nss/lib/util/pqgutil.h b/security/nss/lib/util/pqgutil.h new file mode 100644 index 000000000..1ceb87803 --- /dev/null +++ b/security/nss/lib/util/pqgutil.h @@ -0,0 +1,127 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ +#ifndef _PQGUTIL_H_ +#define _PQGUTIL_H_ 1 + +#include "blapi.h" + +/************************************************************************** + * Return a pointer to a new PQGParams struct that is a duplicate of * + * the one passed as an argument. * + * Return NULL on failure, or if NULL was passed in. * + **************************************************************************/ +extern PQGParams * PQG_DupParams(const PQGParams *src); + + +/************************************************************************** + * Return a pointer to a new PQGParams struct that is constructed from * + * copies of the arguments passed in. * + * Return NULL on failure. * + **************************************************************************/ +extern PQGParams * PQG_NewParams(const SECItem * prime, + const SECItem * subPrime, + const SECItem * base); + + +/************************************************************************** + * Fills in caller's "prime" SECItem with the prime value in params. + * Contents can be freed by calling SECITEM_FreeItem(prime, PR_FALSE); + **************************************************************************/ +extern SECStatus PQG_GetPrimeFromParams(const PQGParams *params, + SECItem * prime); + + +/************************************************************************** + * Fills in caller's "subPrime" SECItem with the prime value in params. + * Contents can be freed by calling SECITEM_FreeItem(subPrime, PR_FALSE); + **************************************************************************/ +extern SECStatus PQG_GetSubPrimeFromParams(const PQGParams *params, + SECItem * subPrime); + + +/************************************************************************** + * Fills in caller's "base" SECItem with the base value in params. + * Contents can be freed by calling SECITEM_FreeItem(base, PR_FALSE); + **************************************************************************/ +extern SECStatus PQG_GetBaseFromParams(const PQGParams *params, SECItem *base); + + +/************************************************************************** + * Free the PQGParams struct and the things it points to. * + **************************************************************************/ +extern void PQG_DestroyParams(PQGParams *params); + + +/************************************************************************** + * Return a pointer to a new PQGVerify struct that is a duplicate of * + * the one passed as an argument. * + * Return NULL on failure, or if NULL was passed in. * + **************************************************************************/ +extern PQGVerify * PQG_DupVerify(const PQGVerify *src); + + +/************************************************************************** + * Return a pointer to a new PQGVerify struct that is constructed from * + * copies of the arguments passed in. * + * Return NULL on failure. * + **************************************************************************/ +extern PQGVerify * PQG_NewVerify(unsigned int counter, const SECItem * seed, + const SECItem * h); + + +/************************************************************************** + * Returns "counter" value from the PQGVerify. + **************************************************************************/ +extern unsigned int PQG_GetCounterFromVerify(const PQGVerify *verify); + +/************************************************************************** + * Fills in caller's "seed" SECItem with the seed value in verify. + * Contents can be freed by calling SECITEM_FreeItem(seed, PR_FALSE); + **************************************************************************/ +extern SECStatus PQG_GetSeedFromVerify(const PQGVerify *verify, SECItem *seed); + + +/************************************************************************** + * Fills in caller's "h" SECItem with the h value in verify. + * Contents can be freed by calling SECITEM_FreeItem(h, PR_FALSE); + **************************************************************************/ +extern SECStatus PQG_GetHFromVerify(const PQGVerify *verify, SECItem * h); + + +/************************************************************************** + * Free the PQGVerify struct and the things it points to. * + **************************************************************************/ +extern void PQG_DestroyVerify(PQGVerify *vfy); + + +#endif diff --git a/security/nss/lib/util/ret_cr16.s b/security/nss/lib/util/ret_cr16.s new file mode 100644 index 000000000..d1fffc577 --- /dev/null +++ b/security/nss/lib/util/ret_cr16.s @@ -0,0 +1,54 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef __LP64__ + .LEVEL 2.0W +#else + .LEVEL 1.1 +#endif + + .CODE ; equivalent to the following two lines +; .SPACE $TEXT$,SORT=8 +; .SUBSPA $CODE$,QUAD=0,ALIGN=4,ACCESS=0x2c,CODE_ONLY,SORT=24 + +ret_cr16 + .PROC + .CALLINFO FRAME=0, NO_CALLS + .EXPORT ret_cr16,ENTRY + .ENTER +; BV %r0(%rp) + BV 0(%rp) + MFCTL %cr16,%ret0 + .LEAVE + .PROCEND + .END diff --git a/security/nss/lib/util/secalgid.c b/security/nss/lib/util/secalgid.c new file mode 100644 index 000000000..7b04941a1 --- /dev/null +++ b/security/nss/lib/util/secalgid.c @@ -0,0 +1,169 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "secoid.h" +#include "secder.h" /* XXX remove this when remove the DERTemplate */ +#include "secasn1.h" +#include "secitem.h" +#include "secerr.h" + +/* XXX Old template; want to expunge it eventually. */ +DERTemplate SECAlgorithmIDTemplate[] = { + { DER_SEQUENCE, + 0, NULL, sizeof(SECAlgorithmID) }, + { DER_OBJECT_ID, + offsetof(SECAlgorithmID,algorithm), }, + { DER_OPTIONAL | DER_ANY, + offsetof(SECAlgorithmID,parameters), }, + { 0, } +}; + +const SEC_ASN1Template SECOID_AlgorithmIDTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(SECAlgorithmID) }, + { SEC_ASN1_OBJECT_ID, + offsetof(SECAlgorithmID,algorithm), }, + { SEC_ASN1_OPTIONAL | SEC_ASN1_ANY, + offsetof(SECAlgorithmID,parameters), }, + { 0, } +}; + +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_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: + 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..9d4d5d465 --- /dev/null +++ b/security/nss/lib/util/secasn1.h @@ -0,0 +1,262 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * 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 "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(PRArenaPool *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); + +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(PRArenaPool *pool, void *dest, + const SEC_ASN1Template *t, + const char *buf, long len); + +extern SECStatus SEC_ASN1DecodeItem(PRArenaPool *pool, void *dest, + const SEC_ASN1Template *t, + SECItem *item); +/* +** Encoding. +*/ + +extern SEC_ASN1EncoderContext *SEC_ASN1EncoderStart(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); + +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(void *src, const SEC_ASN1Template *t, + SEC_ASN1WriteProc output_proc, + void *output_arg); + +extern SECItem * SEC_ASN1EncodeItem(PRArenaPool *pool, SECItem *dest, + void *src, const SEC_ASN1Template *t); + +extern SECItem * SEC_ASN1EncodeInteger(PRArenaPool *pool, + SECItem *dest, long value); + +extern SECItem * SEC_ASN1EncodeUnsignedInteger(PRArenaPool *pool, + SECItem *dest, + 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); + +SEC_END_PROTOS +/************************************************************************/ + +/* + * 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[]; + + +#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..c3d249caf --- /dev/null +++ b/security/nss/lib/util/secasn1d.c @@ -0,0 +1,2872 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * Support for DEcoding ASN.1 data based on BER/DER (Basic/Distinguished + * Encoding Rules). + * + * $Id$ + */ + +#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 *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" +}; +#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) { + cx->status = decodeError; + if (state != NULL) { + PORT_ArenaRelease(cx->our_pool, state->our_mark); + state->our_mark = NULL; + } + return NULL; + } + + 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) + new_state->depth++; + state->child = new_state; + } + + cx->current = new_state; + return new_state; +} + + +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_DYNAMIC | 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 = 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 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; + 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 && state->parent != NULL + && state->parent->indefinite) { + /* + * 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; + } + } + + 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, 8) != 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; + + + /* + * 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; + + /* + * 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); + 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. + * XXX Should we store a NULL here? Or set state to + * afterGroup and let that code do it? + */ + state->place = afterEndOfContents; + } + 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); + 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) { + 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) { + 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) { + 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->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_ArenaRelease (state->top->our_pool, state->our_mark); + if (error && state->top->their_pool == NULL) { + /* + * XXX We need to free anything allocated. + */ + PORT_Assert (0); + } + 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; +} + + +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; + + 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; + + if (len == 0) { + state->top->status = needBytes; + return 0; + } + + if (state->pending < len) + len = state->pending; + + item = (SECItem *)(state->dest); + if (item != NULL && item->data != NULL) { + PORT_Memcpy (item->data + item->len, buf, len); + item->len += len; + } + state->pending -= len; + if (state->pending == 0) + state->place = beforeEndOfContents; + + return len; +} + + +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 (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->pending > 0); + PORT_Assert (state->place == duringBitString); + + 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; + 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); + PORT_Assert (child_consumed <= state->pending); + + 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); + PORT_Assert (child_consumed <= state->pending); + + 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); + 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); + PORT_Assert (child_consumed <= state->pending); + 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); + 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) { + 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->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 = 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; + if (state->subitems_head != 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; + } + + PORT_Assert (placep != NULL); + *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; + } else if (placep != NULL) { + *placep = 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. + * (Only IMPLICIT or POINTER should encounter such; all other cases + * should have confirmed a tag *before* pushing a child.) + */ + state->missing = state->child->missing; + if (state->missing) { + PORT_Assert (state->place == afterImplicit + || state->place == afterPointer); + state->found_tag_number = state->child->found_tag_number; + state->found_tag_modifiers = state->child->found_tag_modifiers; + } + + /* + * 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) +{ + 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); + PORT_Assert (state->child->consumed <= state->pending); + 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, + state->dest, 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 ) { + 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; + } + + state->consumed += child->consumed; + + /* cargo'd from next_in_sequence innards */ + if( state->pending ) { + PORT_Assert(!state->indefinite); + PORT_Assert(child->consumed <= state->pending); + 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); + child = sec_asn1d_init_state_based_on_template(child); + if( (sec_asn1d_state *)NULL == child ) { + return (sec_asn1d_state *)NULL; + } + + child->optional = PR_TRUE; + child->place = afterIdentifier; + state->top->current = child; + + return child; + } else { + if( (void *)NULL != state->dest ) { + /* Store the enum */ + int *which = (int *)((char *)state->dest + state->theTemplate->offset); + *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); +} + +#ifdef DEBUG_ASN1D_STATES +static void +dump_states +( + SEC_ASN1DecoderContext *cx +) +{ + sec_asn1d_state *state; + + for( state = cx->current; state->parent; state = state->parent ) { + ; + } + + for( ; state; state = state->child ) { + int i; + for( i = 0; i < state->depth; i++ ) { + printf(" "); + } + + printf("%s: template[0]->kind = 0x%02x, expect tag number = 0x%02x\n", + (state == cx->current) ? "STATE" : "State", + state->theTemplate->kind, state->expect_tag_number); + } + + 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; + + + 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\n", + (state->place >= 0 && state->place <= notInUse) ? + place_names[ state->place ] : "(undefined)", + (unsigned int)((unsigned char *)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); + 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: + /* XXX comment! */ + 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); + + /* 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) + 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) { + 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_FALSE); + + 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 */ +} + + +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, + SECItem *item) +{ + return SEC_ASN1Decode (poolp, dest, theTemplate, + (char *) item->data, item->len); +} + + +/* + * 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_AnyTemplate[] = { + { SEC_ASN1_ANY | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) } +}; + +const SEC_ASN1Template SEC_PointerToAnyTemplate[] = { + { SEC_ASN1_POINTER, 0, SEC_AnyTemplate } +}; + +const SEC_ASN1Template SEC_SequenceOfAnyTemplate[] = { + { SEC_ASN1_SEQUENCE_OF, 0, SEC_AnyTemplate } +}; + +const SEC_ASN1Template SEC_SetOfAnyTemplate[] = { + { SEC_ASN1_SET_OF, 0, SEC_AnyTemplate } +}; + +const SEC_ASN1Template SEC_BitStringTemplate[] = { + { SEC_ASN1_BIT_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) } +}; + +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_BMPStringTemplate[] = { + { SEC_ASN1_BMP_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) } +}; + +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_BooleanTemplate[] = { + { SEC_ASN1_BOOLEAN, 0, NULL, sizeof(SECItem) } +}; + +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 } +}; + +const SEC_ASN1Template SEC_EnumeratedTemplate[] = { + { SEC_ASN1_ENUMERATED, 0, NULL, sizeof(SECItem) } +}; + +const SEC_ASN1Template SEC_PointerToEnumeratedTemplate[] = { + { SEC_ASN1_POINTER, 0, SEC_EnumeratedTemplate } +}; + +const SEC_ASN1Template SEC_SequenceOfEnumeratedTemplate[] = { + { SEC_ASN1_SEQUENCE_OF, 0, SEC_EnumeratedTemplate } +}; + +const SEC_ASN1Template SEC_SetOfEnumeratedTemplate[] = { + { SEC_ASN1_SET_OF, 0, SEC_EnumeratedTemplate } +}; + +const SEC_ASN1Template SEC_GeneralizedTimeTemplate[] = { + { SEC_ASN1_GENERALIZED_TIME | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)} +}; + +const SEC_ASN1Template SEC_PointerToGeneralizedTimeTemplate[] = { + { SEC_ASN1_POINTER, 0, SEC_GeneralizedTimeTemplate } +}; + +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_IA5StringTemplate[] = { + { SEC_ASN1_IA5_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) } +}; + +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_IntegerTemplate[] = { + { SEC_ASN1_INTEGER, 0, NULL, sizeof(SECItem) } +}; + +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_NullTemplate[] = { + { SEC_ASN1_NULL, 0, NULL, sizeof(SECItem) } +}; + +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_ObjectIDTemplate[] = { + { SEC_ASN1_OBJECT_ID, 0, NULL, sizeof(SECItem) } +}; + +const SEC_ASN1Template SEC_PointerToObjectIDTemplate[] = { + { SEC_ASN1_POINTER, 0, SEC_ObjectIDTemplate } +}; + +const SEC_ASN1Template SEC_SequenceOfObjectIDTemplate[] = { + { SEC_ASN1_SEQUENCE_OF, 0, SEC_ObjectIDTemplate } +}; + +const SEC_ASN1Template SEC_SetOfObjectIDTemplate[] = { + { SEC_ASN1_SET_OF, 0, SEC_ObjectIDTemplate } +}; + +const SEC_ASN1Template SEC_OctetStringTemplate[] = { + { SEC_ASN1_OCTET_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) } +}; + +const SEC_ASN1Template SEC_PointerToOctetStringTemplate[] = { + { SEC_ASN1_POINTER | SEC_ASN1_MAY_STREAM, 0, SEC_OctetStringTemplate } +}; + +const SEC_ASN1Template SEC_SequenceOfOctetStringTemplate[] = { + { SEC_ASN1_SEQUENCE_OF, 0, SEC_OctetStringTemplate } +}; + +const SEC_ASN1Template SEC_SetOfOctetStringTemplate[] = { + { SEC_ASN1_SET_OF, 0, SEC_OctetStringTemplate } +}; + +const SEC_ASN1Template SEC_PrintableStringTemplate[] = { + { SEC_ASN1_PRINTABLE_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)} +}; + +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 } +}; + +const SEC_ASN1Template SEC_T61StringTemplate[] = { + { SEC_ASN1_T61_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) } +}; + +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 } +}; + +const SEC_ASN1Template SEC_UniversalStringTemplate[] = { + { SEC_ASN1_UNIVERSAL_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)} +}; + +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_UTCTimeTemplate[] = { + { SEC_ASN1_UTC_TIME | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) } +}; + +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_UTF8StringTemplate[] = { + { SEC_ASN1_UTF8_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem)} +}; + +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 } +}; + +const SEC_ASN1Template SEC_VisibleStringTemplate[] = { + { SEC_ASN1_VISIBLE_STRING | SEC_ASN1_MAY_STREAM, 0, NULL, sizeof(SECItem) } +}; + +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 } +}; + + +/* + * 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 } +}; diff --git a/security/nss/lib/util/secasn1e.c b/security/nss/lib/util/secasn1e.c new file mode 100644 index 000000000..88a0e2136 --- /dev/null +++ b/security/nss/lib/util/secasn1e.c @@ -0,0 +1,1463 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * 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 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 explicit, /* we are handling an explicit 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 */ +} 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, + 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 explicit, is_string, may_stream, optional, universal; + unsigned char tag_modifiers; + unsigned long encode_kind, under_kind; + unsigned long tag_number; + + + encode_kind = state->theTemplate->kind; + + 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 */ + + 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_CHOICE ) { + under_kind = SEC_ASN1_CHOICE; + } else + + if ((encode_kind & (SEC_ASN1_POINTER | SEC_ASN1_INLINE)) || (!universal + && !explicit)) { + const SEC_ASN1Template *subt; + void *src; + + PORT_Assert ((encode_kind & (SEC_ASN1_ANY | SEC_ASN1_SKIP)) == 0); + + sec_asn1e_scrub_state (state); + + if (encode_kind & SEC_ASN1_POINTER) { + /* + * XXX This used to PORT_Assert (encode_kind == SEC_ASN1_POINTER); + * but that was too restrictive. This needs to be fixed, + * probably copying what the decoder now checks for, and + * adding a big comment here to explain what the checks mean. + */ + 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; + } 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 = encode_kind & SEC_ASN1_TAG_MASK + & ~SEC_ASN1_TAGNUM_MASK; + state->tag_number = encode_kind & SEC_ASN1_TAGNUM_MASK; + + state->place = afterImplicit; + state->optional = optional; + } + } + + subt = SEC_ASN1GetSubtemplate (state->theTemplate, state->src, PR_TRUE); + state = sec_asn1e_push_state (state->top, subt, src, PR_FALSE); + if (state == NULL) + return NULL; + + 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.). + */ + + under_kind = state->theTemplate->kind; + if (under_kind & SEC_ASN1_MAY_STREAM) { + may_stream = PR_TRUE; + under_kind &= ~SEC_ASN1_MAY_STREAM; + } + } 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?) + */ + PORT_Assert ((under_kind & (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)) == 0); + + 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 = 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 = tag_number; + state->underlying_kind = under_kind; + state->explicit = explicit; + state->may_stream = may_stream; + state->is_string = is_string; + state->optional = optional; + + 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; + int which = *(int *)((char *)src + theTemplate->offset); + + 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 *noheaderp) +{ + unsigned long encode_kind, underlying_kind; + PRBool explicit, optional, universal; + unsigned long len; + + encode_kind = theTemplate->kind; + + 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 */ + + /* We have already decided we are not streaming. */ + 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_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[indx].offset); + + return sec_asn1e_contents_length(&theTemplate[indx], src2, noheaderp); + } + + 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) { + /* + * XXX This used to PORT_Assert (encode_kind == SEC_ASN1_POINTER); + * but that was too restrictive. This needs to be fixed, + * probably copying what the decoder now checks for, and + * adding a big comment here to explain what the checks mean. + * Alternatively, the check here could be omitted altogether + * just letting sec_asn1e_init_state_based_on_template + * do it, since that routine can do better error handling, too. + */ + src = *(void **)src; + if (src == NULL) { + if (optional) + *noheaderp = PR_TRUE; + else + *noheaderp = PR_FALSE; + return 0; + } + } else if (encode_kind & SEC_ASN1_INLINE) { + /* check that there are no extraneous bits */ + PORT_Assert (encode_kind == SEC_ASN1_INLINE && !optional); + } + + src = (char *)src + theTemplate->offset; + + if (explicit) { + len = sec_asn1e_contents_length (theTemplate, src, noheaderp); + if (len == 0 && optional) { + *noheaderp = PR_TRUE; + } else if (*noheaderp) { + /* + * Okay, *we* do not want to add in a header, but our + * caller still does. + */ + *noheaderp = PR_FALSE; + } else { + /* + * XXX The 1 below is the presumed length of the identifier; + * to support a high-tag-number this would need to be smarter. + */ + len += 1 + SEC_ASN1LengthLength (len); + } + return len; + } + + underlying_kind = theTemplate->kind; + underlying_kind &= ~SEC_ASN1_MAY_STREAM; + + /* XXX Should we recurse here? */ + } else { + 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); + *noheaderp = PR_TRUE; + return 0; + } + + /* Having any of these bits is not expected here... */ + PORT_Assert ((underlying_kind & (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)) == 0); + + 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, noheaderp); + } 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, noheaderp); + 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 (!*noheaderp) + 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, noheaderp); + 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 (!*noheaderp) + 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; + + default: + len = ((SECItem *)src)->len; + break; + } + + if ((len == 0 && optional) || underlying_kind == SEC_ASN1_ANY) + *noheaderp = PR_TRUE; + else + *noheaderp = PR_FALSE; + + return len; +} + + +static void +sec_asn1e_write_header (sec_asn1e_state *state) +{ + unsigned long contents_length; + unsigned char tag_number, tag_modifiers; + + 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 ) { + void *src2; + 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], + state->src, PR_TRUE); + + if( (sec_asn1e_state *)NULL != 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; + } + + if (state->top->streaming && state->may_stream + && (state->top->from_buf || !state->is_string)) { + /* + * We need to put out an indefinite-length encoding. + */ + state->indefinite = PR_TRUE; + /* + * 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). + */ + 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; + } else { + PRBool noheader; + + /* + * We are doing a definite-length encoding. First we have to + * walk the data structure to calculate the entire contents length. + */ + contents_length = sec_asn1e_contents_length (state->theTemplate, + state->src, &noheader); + /* + * 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 (noheader || (contents_length == 0 && state->optional)) { + state->place = afterContents; + return; + } + } + + sec_asn1e_write_identifier_bytes (state, 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->explicit) { + state->place = afterContents; + state = sec_asn1e_push_state (state->top, + SEC_ASN1GetSubtemplate(state->theTemplate, + state->src, + PR_TRUE), + 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 (sec_asn1e_state *state, + const char *buf, unsigned long len) +{ + PORT_Assert (state->place == duringContents); + + if (state->top->from_buf) { + /* + * 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 = 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; + } else { + 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 = (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; + +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) { + PORT_Assert (buf != NULL && len != 0); + cx->status = keepGoing; + } + + while (cx->status == keepGoing) { + state = cx->current; + switch (state->place) { + case beforeHeader: + sec_asn1e_write_header (state); + break; + case duringContents: + sec_asn1e_write_contents (state, buf, len); + 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 (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_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 (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->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, 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 = 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] = 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); +} + + +extern 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..1e87ed12c --- /dev/null +++ b/security/nss/lib/util/secasn1t.h @@ -0,0 +1,259 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * Types for encoding/decoding of ASN.1 using BER/DER (Basic/Distinguished + * Encoding Rules). + * + * $Id$ + */ + +#ifndef _SECASN1T_H_ +#define _SECASN1T_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 +#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_TELETEX_STRING SEC_ASN1_T61_STRING +#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 + +/* +** 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 */ + +/* 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) + +/* +** 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_ChooseASN1TemplateFunc)(void *arg, + PRBool enc); + +/* +** 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, + SEC_ASN1_Length, + SEC_ASN1_Contents, + SEC_ASN1_EndOfContents +} 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..ea068893b --- /dev/null +++ b/security/nss/lib/util/secasn1u.c @@ -0,0 +1,106 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * 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; + + PORT_Assert (theTemplate->sub != NULL); + if (theTemplate->kind & SEC_ASN1_DYNAMIC) { + SEC_ChooseASN1TemplateFunc chooser, *chooserp; + + chooserp = (SEC_ChooseASN1TemplateFunc *) theTemplate->sub; + if (chooserp == NULL || *chooserp == NULL) + return NULL; + chooser = *chooserp; + if (thing != NULL) + thing = (char *)thing - theTemplate->offset; + subt = (* chooser)(thing, encoding); + } else { + subt = (SEC_ASN1Template*)theTemplate->sub; + } + + return subt; +} diff --git a/security/nss/lib/util/seccomon.h b/security/nss/lib/util/seccomon.h new file mode 100644 index 000000000..707db8bbc --- /dev/null +++ b/security/nss/lib/util/seccomon.h @@ -0,0 +1,109 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * 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 "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, + siClearDataBuffer, + siCipherDataBuffer, + siDERCertBuffer, + siEncodedCertBuffer, + siDERNameBuffer, + siEncodedNameBuffer, + siAsciiNameString, + siAsciiString, + siDEROID +} 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..3f957ab9c --- /dev/null +++ b/security/nss/lib/util/secder.h @@ -0,0 +1,193 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef _SECDER_H_ +#define _SECDER_H_ + +/* + * secder.h - public data structures and prototypes for the DER encoding and + * decoding utilities library + * + * $Id$ + */ + +#include <time.h> +#include "plarena.h" +#include "prlong.h" + +#include "seccomon.h" +#include "secdert.h" + +SEC_BEGIN_PROTOS + +/* +** Decode a piece of der encoded data. +** "dest" points to a structure that will be filled in with the +** decoding results. (NOTE: it should be zeroed before calling; +** optional/missing fields are not zero-filled by DER_Decode.) +** "t" is a template structure which defines the shape of the +** expected data. +** "src" is the der encoded data. +** NOTE: substructures of "dest" will be allocated as needed from +** "arena", but data subfields will point directly into the buffer +** passed in as src->data. That is, the resulting "dest" structure +** will contain pointers back into src->data, which must remain +** active (allocated) and unmodified for as long as "dest" is active. +** If this is a potential problem, you may want to just dup the buffer +** (allocated from "arena", probably) and pass *that* in instead. +*/ +extern SECStatus DER_Decode(PRArenaPool *arena, void *dest, DERTemplate *t, + SECItem *src); + +/* +** 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(PRArenaPool *arena, SECItem *dest, DERTemplate *t, + void *src); + +extern SECStatus DER_Lengths(SECItem *item, int *header_len_p, uint32 *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, + uint32 encodingLen); + +/* +** Return the number of bytes it will take to hold a der encoded length. +*/ +extern int DER_LengthLength(uint32 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(PRArenaPool *arena, SECItem *dst, int32 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(PRArenaPool *arena, SECItem *dst, uint32 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 a "UNIX" time value to a der encoded time value. +** "result" is the der encoded time (memory is allocated) +** "time" is the "UNIX" time value (Since Jan 1st, 1970). +** The caller is responsible for freeing up the buffer which +** result->data points to upon a successfull operation. +*/ +extern SECStatus DER_TimeToUTCTime(SECItem *result, int64 time); + +/* +** Convert an ascii encoded time value (according to DER rules) into +** a UNIX time value. +** "result" the resulting "UNIX" time +** "string" the der notation ascii value to decode +*/ +extern SECStatus DER_AsciiToTime(int64 *result, char *string); + +/* +** Same as DER_AsciiToTime except takes an SECItem instead of a string +*/ +extern SECStatus DER_UTCTimeToTime(int64 *result, 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); + +/* +** Convert a int64 time to a DER encoded Generalized time +*/ +extern SECStatus DER_TimeToGeneralizedTime(SECItem *dst, int64 gmttime); + +/* +** Convert a DER encoded Generalized time value into a UNIX time value. +** "dst" the resulting "UNIX" time +** "string" the der notation ascii value to decode +*/ +extern SECStatus DER_GeneralizedTimeToTime(int64 *dst, SECItem *time); + +/* +** Convert from a int64 UTC time value to a formatted ascii value. The +** caller is responsible for deallocating the returned buffer. +*/ +extern char *CERT_UTCTime2FormattedAscii (int64 utcTime, char *format); + + +/* +** Convert from a int64 Generalized time value to a formatted ascii value. The +** caller is responsible for deallocating the returned buffer. +*/ +extern char *CERT_GenTime2FormattedAscii (int64 genTime, char *format); + +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..86f3451cf --- /dev/null +++ b/security/nss/lib/util/secdert.h @@ -0,0 +1,170 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef _SECDERT_H_ +#define _SECDERT_H_ +/* + * secdert.h - public data structures for the DER encoding and + * decoding utilities library + * + * $Id$ + */ + +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; \ +} + +extern DERTemplate SECAnyTemplate[]; +extern DERTemplate SECBitStringTemplate[]; +extern DERTemplate SECBooleanTemplate[]; +extern DERTemplate SECIA5StringTemplate[]; +extern DERTemplate SECIntegerTemplate[]; +extern DERTemplate SECNullTemplate[]; +extern DERTemplate SECObjectIDTemplate[]; +extern DERTemplate SECOctetStringTemplate[]; +extern DERTemplate SECPrintableStringTemplate[]; +extern DERTemplate SECT61StringTemplate[]; +extern DERTemplate SECUTCTimeTemplate[]; +extern DERTemplate SECAlgorithmIDTemplate[]; + +#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..020829b84 --- /dev/null +++ b/security/nss/lib/util/secdig.c @@ -0,0 +1,230 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * + * $Id$ + */ +#include "secdig.h" + +#include "secoid.h" +#include "secasn1.h" +#include "secerr.h" + +/* + * XXX OLD Template. Once all uses have been switched over to new one, + * remove this. + */ +DERTemplate SGNDigestInfoTemplate[] = { + { DER_SEQUENCE, + 0, NULL, sizeof(SGNDigestInfo) }, + { DER_INLINE, + offsetof(SGNDigestInfo,digestAlgorithm), + SECAlgorithmIDTemplate, }, + { DER_OCTET_STRING, + offsetof(SGNDigestInfo,digest), }, + { 0, } +}; + +/* 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 } +}; + +/* + * 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: + 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; + + arena = PORT_NewArena(SEC_ASN1_DEFAULT_ARENA_SIZE); + if(arena == NULL) + return NULL; + + di = (SGNDigestInfo *)PORT_ArenaZAlloc(arena, sizeof(SGNDigestInfo)); + if(di != NULL) + { + di->arena = arena; + rv = SEC_ASN1DecodeItem(arena, di, sgn_DigestInfoTemplate, didata); + } + + if((di == NULL) || (rv != SECSuccess)) + { + PORT_FreeArena(arena, PR_TRUE); + 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..bd2703f65 --- /dev/null +++ b/security/nss/lib/util/secdig.h @@ -0,0 +1,132 @@ +/* + * crypto.h - public data structures and prototypes for the crypto library + * + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * + * $Id$ + */ + +#ifndef _SECDIG_H_ +#define _SECDIG_H_ + +#include "secdigt.h" + +#include "seccomon.h" +#include "secasn1t.h" +#include "secdert.h" + + +extern const SEC_ASN1Template sgn_DigestInfoTemplate[]; +extern DERTemplate SGNDigestInfoTemplate[]; + + +SEC_BEGIN_PROTOS + +/****************************************/ +/* +** 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(PRArenaPool *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(PRArenaPool *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..fea6daa99 --- /dev/null +++ b/security/nss/lib/util/secdigt.h @@ -0,0 +1,57 @@ +/* + * secdigt.h - public data structures for digestinfos from the util lib. + * + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + * + * $Id$ + */ + +#ifndef _SECDIGT_H_ +#define _SECDIGT_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..b0aab7894 --- /dev/null +++ b/security/nss/lib/util/secerr.h @@ -0,0 +1,184 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef __SEC_ERR_H_ +#define __SEC_ERR_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), +/* UNUSED (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) + +} 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..a18b1243b --- /dev/null +++ b/security/nss/lib/util/secinit.c @@ -0,0 +1,50 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#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..411078bee --- /dev/null +++ b/security/nss/lib/util/secitem.c @@ -0,0 +1,246 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * 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; + + 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 (arena != NULL) { + PORT_ArenaUnmark(arena, mark); + } + return(result); + +loser: + if (arena != NULL) { + 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); + } + } + 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; + + 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 (SECITEM_CompareItem(a, b) == SECEqual) + return PR_TRUE; + + return PR_FALSE; +} + +SECItem * +SECITEM_DupItem(const SECItem *from) +{ + SECItem *to; + + if ( from == NULL ) { + return(NULL); + } + + to = (SECItem *)PORT_Alloc(sizeof(SECItem)); + if ( to == NULL ) { + return(NULL); + } + + to->data = (unsigned char *)PORT_Alloc(from->len); + if ( to->data == NULL ) { + PORT_Free(to); + return(NULL); + } + + to->len = from->len; + PORT_Memcpy(to->data, from->data, to->len); + + return(to); +} + +SECStatus +SECITEM_CopyItem(PRArenaPool *arena, SECItem *to, const SECItem *from) +{ + 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)); + } + } +} + +char * +BTOA_ConvertItemToAscii (SECItem *isrc) +{ + return BTOA_DataToAscii (isrc->data, isrc->len); +} diff --git a/security/nss/lib/util/secitem.h b/security/nss/lib/util/secitem.h new file mode 100644 index 000000000..3928cad98 --- /dev/null +++ b/security/nss/lib/util/secitem.h @@ -0,0 +1,106 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef _SECITEM_H_ +#define _SECITEM_H_ +/* + * secitem.h - public data structures and prototypes for handling + * SECItems + * + * $Id$ + */ + +#include "plarena.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 for the item, not the item itself. The item structure +** is allocated zero-filled; the data buffer is not zeroed. +** +** 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(PRArenaPool *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(PRArenaPool *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(PRArenaPool *arena, SECItem *to, + const SECItem *from); + +/* +** Allocate an item and copy "from" into it. +*/ +extern SECItem *SECITEM_DupItem(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); + +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..320f19fd9 --- /dev/null +++ b/security/nss/lib/util/secoid.c @@ -0,0 +1,1499 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "secoid.h" +#include "mcom_db.h" +#include "pkcs11t.h" +#include "secmodt.h" +#include "secitem.h" +#include "secerr.h" + +/* MISSI Mosaic Object ID space */ +#define MISSI 0x60, 0x86, 0x48, 0x01, 0x65, 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 + +/** + ** 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 +/* netscape certificate extensions */ +#define NETSCAPE_CERT_EXT NETSCAPE_OID, 0x01 + +/* netscape data types */ +#define NETSCAPE_DATA_TYPE NETSCAPE_OID, 0x02 + +/* netscape directory oid - owned by Tim Howes(howes@netscape.com) */ +#define NETSCAPE_DIRECTORY NETSCAPE_OID, 0x03 + +/* various policy type OIDs */ +#define NETSCAPE_POLICY NETSCAPE_OID, 0x04 + +/* netscape cert server oid */ +#define NETSCAPE_CERT_SERVER NETSCAPE_OID, 0x05 +#define NETSCAPE_CERT_SERVER_CRMF NETSCAPE_CERT_SERVER, 0x01 + +/* various algorithm OIDs */ +#define NETSCAPE_ALGS NETSCAPE_OID, 0x06 + +/* Netscape Other Name Types */ + +#define NETSCAPE_NAME_COMPONENTS NETSCAPE_OID, 0x07 + +/* 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 + +/* 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 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_ID_PKIP PKIX, 5 +#define PKIX_ID_REGCTRL PKIX_ID_PKIP, 1 +#define PKIX_ID_REGINFO PKIX_ID_PKIP, 2 + + +static unsigned char md2[] = { DIGEST, 0x02 }; +static unsigned char md4[] = { DIGEST, 0x04 }; +static unsigned char md5[] = { DIGEST, 0x05 }; +static unsigned char sha1[] = { ALGORITHM, 0x1a }; +static unsigned char rc2cbc[] = { CIPHER, 0x02 }; +static unsigned char rc4[] = { CIPHER, 0x04 }; +static unsigned char desede3cbc[] = { CIPHER, 0x07 }; +static unsigned char rc5cbcpad[] = { CIPHER, 0x09 }; +static unsigned char desecb[] = { ALGORITHM, 0x06 }; +static unsigned char descbc[] = { ALGORITHM, 0x07 }; +static unsigned char desofb[] = { ALGORITHM, 0x08 }; +static unsigned char descfb[] = { ALGORITHM, 0x09 }; +static unsigned char desmac[] = { ALGORITHM, 0x0a }; +static unsigned char desede[] = { ALGORITHM, 0x11 }; +static unsigned char isoSHAWithRSASignature[] = { ALGORITHM, 0xf }; +static unsigned char pkcs1RSAEncryption[] = { PKCS1, 0x01 }; +static unsigned char pkcs1MD2WithRSAEncryption[] = { PKCS1, 0x02 }; +static unsigned char pkcs1MD4WithRSAEncryption[] = { PKCS1, 0x03 }; +static unsigned char pkcs1MD5WithRSAEncryption[] = { PKCS1, 0x04 }; +static unsigned char pkcs1SHA1WithRSAEncryption[] = { PKCS1, 0x05 }; +static unsigned char pkcs5PbeWithMD2AndDEScbc[] = { PKCS5, 0x01 }; +static unsigned char pkcs5PbeWithMD5AndDEScbc[] = { PKCS5, 0x03 }; +static unsigned char pkcs5PbeWithSha1AndDEScbc[] = { PKCS5, 0x0a }; +static unsigned char pkcs7[] = { PKCS7 }; +static unsigned char pkcs7Data[] = { PKCS7, 0x01 }; +static unsigned char pkcs7SignedData[] = { PKCS7, 0x02 }; +static unsigned char pkcs7EnvelopedData[] = { PKCS7, 0x03 }; +static unsigned char pkcs7SignedEnvelopedData[] = { PKCS7, 0x04 }; +static unsigned char pkcs7DigestedData[] = { PKCS7, 0x05 }; +static unsigned char pkcs7EncryptedData[] = { PKCS7, 0x06 }; +static unsigned char pkcs9EmailAddress[] = { PKCS9, 0x01 }; +static unsigned char pkcs9UnstructuredName[] = { PKCS9, 0x02 }; +static unsigned char pkcs9ContentType[] = { PKCS9, 0x03 }; +static unsigned char pkcs9MessageDigest[] = { PKCS9, 0x04 }; +static unsigned char pkcs9SigningTime[] = { PKCS9, 0x05 }; +static unsigned char pkcs9CounterSignature[] = { PKCS9, 0x06 }; +static unsigned char pkcs9ChallengePassword[] = { PKCS9, 0x07 }; +static unsigned char pkcs9UnstructuredAddress[] = { PKCS9, 0x08 }; +static unsigned char pkcs9ExtendedCertificateAttributes[] = { PKCS9, 0x09 }; +static unsigned char pkcs9SMIMECapabilities[] = { PKCS9, 15 }; +static unsigned char x520CommonName[] = { X520_ATTRIBUTE_TYPE, 3 }; +static unsigned char x520CountryName[] = { X520_ATTRIBUTE_TYPE, 6 }; +static unsigned char x520LocalityName[] = { X520_ATTRIBUTE_TYPE, 7 }; +static unsigned char x520StateOrProvinceName[] = { X520_ATTRIBUTE_TYPE, 8 }; +static unsigned char x520OrgName[] = { X520_ATTRIBUTE_TYPE, 10 }; +static unsigned char x520OrgUnitName[] = { X520_ATTRIBUTE_TYPE, 11 }; +static unsigned char x520DnQualifier[] = { X520_ATTRIBUTE_TYPE, 46 }; + +static unsigned char nsTypeGIF[] = { NETSCAPE_DATA_TYPE, 0x01 }; +static unsigned char nsTypeJPEG[] = { NETSCAPE_DATA_TYPE, 0x02 }; +static unsigned char nsTypeURL[] = { NETSCAPE_DATA_TYPE, 0x03 }; +static unsigned char nsTypeHTML[] = { NETSCAPE_DATA_TYPE, 0x04 }; +static unsigned char nsTypeCertSeq[] = { NETSCAPE_DATA_TYPE, 0x05 }; +static unsigned char missiCertKEADSSOld[] = { MISSI_OLD_KEA_DSS }; +static unsigned char missiCertDSSOld[] = { MISSI_OLD_DSS }; +static unsigned char missiCertKEADSS[] = { MISSI_KEA_DSS }; +static unsigned char missiCertDSS[] = { MISSI_DSS }; +static unsigned char missiCertKEA[] = { MISSI_KEA }; +static unsigned char missiCertAltKEA[] = { MISSI_ALT_KEA }; +static unsigned char x500RSAEncryption[] = { X500_ALG_ENCRYPTION, 0x01 }; + +/* added for alg 1485 */ +static unsigned char rfc1274Uid[] = { RFC1274_ATTR_TYPE, 1 }; +static unsigned char rfc1274Mail[] = { RFC1274_ATTR_TYPE, 3 }; +static unsigned char rfc2247DomainComponent[] = { RFC2247_ATTR_TYPE, 25 }; + +/* Netscape private certificate extensions */ +static unsigned char nsCertExtNetscapeOK[] = { NS_CERT_EXT, 1 }; +static unsigned char nsCertExtIssuerLogo[] = { NS_CERT_EXT, 2 }; +static unsigned char nsCertExtSubjectLogo[] = { NS_CERT_EXT, 3 }; +static unsigned char nsExtCertType[] = { NETSCAPE_CERT_EXT, 0x01 }; +static unsigned char nsExtBaseURL[] = { NETSCAPE_CERT_EXT, 0x02 }; +static unsigned char nsExtRevocationURL[] = { NETSCAPE_CERT_EXT, 0x03 }; +static unsigned char nsExtCARevocationURL[] = { NETSCAPE_CERT_EXT, 0x04 }; +static unsigned char nsExtCACRLURL[] = { NETSCAPE_CERT_EXT, 0x05 }; +static unsigned char nsExtCACertURL[] = { NETSCAPE_CERT_EXT, 0x06 }; +static unsigned char nsExtCertRenewalURL[] = { NETSCAPE_CERT_EXT, 0x07 }; +static unsigned char nsExtCAPolicyURL[] = { NETSCAPE_CERT_EXT, 0x08 }; +static unsigned char nsExtHomepageURL[] = { NETSCAPE_CERT_EXT, 0x09 }; +static unsigned char nsExtEntityLogo[] = { NETSCAPE_CERT_EXT, 0x0a }; +static unsigned char nsExtUserPicture[] = { NETSCAPE_CERT_EXT, 0x0b }; +static unsigned char nsExtSSLServerName[] = { NETSCAPE_CERT_EXT, 0x0c }; +static unsigned char nsExtComment[] = { NETSCAPE_CERT_EXT, 0x0d }; + +/* the following 2 extensions are defined for and used by Cartman(NSM) */ +static unsigned char nsExtLostPasswordURL[] = { NETSCAPE_CERT_EXT, 0x0e }; +static unsigned char nsExtCertRenewalTime[] = { NETSCAPE_CERT_EXT, 0x0f }; + +#define NETSCAPE_CERT_EXT_AIA NETSCAPE_CERT_EXT, 0x10 + +static unsigned char nsExtAIACertRenewal[] = { NETSCAPE_CERT_EXT_AIA, 0x01 }; + +static unsigned char nsExtCertScopeOfUse[] = { NETSCAPE_CERT_EXT, 0x11 }; + +static unsigned char nsKeyUsageGovtApproved[] = { NETSCAPE_POLICY, 0x01 }; + + +/* Standard x.509 v3 Certificate Extensions */ +static unsigned char x509SubjectDirectoryAttr[] = { ID_CE_OID, 9 }; +static unsigned char x509SubjectKeyID[] = { ID_CE_OID, 14 }; +static unsigned char x509KeyUsage[] = { ID_CE_OID, 15 }; +static unsigned char x509PrivateKeyUsagePeriod[] = { ID_CE_OID, 16 }; +static unsigned char x509SubjectAltName[] = { ID_CE_OID, 17 }; +static unsigned char x509IssuerAltName[] = { ID_CE_OID, 18 }; +static unsigned char x509BasicConstraints[] = { ID_CE_OID, 19 }; +static unsigned char x509NameConstraints[] = { ID_CE_OID, 30 }; +static unsigned char x509CRLDistPoints[] = { ID_CE_OID, 31 }; +static unsigned char x509CertificatePolicies[] = { ID_CE_OID, 32 }; +static unsigned char x509PolicyMappings[] = { ID_CE_OID, 33 }; +static unsigned char x509PolicyConstraints[] = { ID_CE_OID, 34 }; +static unsigned char x509AuthKeyID[] = { ID_CE_OID, 35}; +static unsigned char x509ExtKeyUsage[] = { ID_CE_OID, 37}; +static unsigned char x509AuthInfoAccess[] = { PKIX_CERT_EXTENSIONS, 1 }; + +/* Standard x.509 v3 CRL Extensions */ +static unsigned char x509CrlNumber[] = { ID_CE_OID, 20}; +static unsigned char x509ReasonCode[] = { ID_CE_OID, 21}; +static unsigned char x509InvalidDate[] = { ID_CE_OID, 24}; + +/* pkcs 12 additions */ +static unsigned char pkcs12[] = { PKCS12 }; +static unsigned char pkcs12ModeIDs[] = { PKCS12_MODE_IDS }; +static unsigned char pkcs12ESPVKIDs[] = { PKCS12_ESPVK_IDS }; +static unsigned char pkcs12BagIDs[] = { PKCS12_BAG_IDS }; +static unsigned char pkcs12CertBagIDs[] = { PKCS12_CERT_BAG_IDS }; +static unsigned char pkcs12OIDs[] = { PKCS12_OIDS }; +static unsigned char pkcs12PBEIDs[] = { PKCS12_PBE_IDS }; +static unsigned char pkcs12EnvelopingIDs[] = { PKCS12_ENVELOPING_IDS }; +static unsigned char pkcs12SignatureIDs[] = { PKCS12_SIGNATURE_IDS }; +static unsigned char pkcs12PKCS8KeyShrouding[] = { PKCS12_ESPVK_IDS, 0x01 }; +static unsigned char pkcs12KeyBagID[] = { PKCS12_BAG_IDS, 0x01 }; +static unsigned char pkcs12CertAndCRLBagID[] = { PKCS12_BAG_IDS, 0x02 }; +static unsigned char pkcs12SecretBagID[] = { PKCS12_BAG_IDS, 0x03 }; +static unsigned char pkcs12X509CertCRLBag[] = { PKCS12_CERT_BAG_IDS, 0x01 }; +static unsigned char pkcs12SDSICertBag[] = { PKCS12_CERT_BAG_IDS, 0x02 }; +static unsigned char pkcs12PBEWithSha1And128BitRC4[] = { PKCS12_PBE_IDS, 0x01 }; +static unsigned char pkcs12PBEWithSha1And40BitRC4[] = { PKCS12_PBE_IDS, 0x02 }; +static unsigned char pkcs12PBEWithSha1AndTripleDESCBC[] = { PKCS12_PBE_IDS, 0x03 }; +static unsigned char pkcs12PBEWithSha1And128BitRC2CBC[] = { PKCS12_PBE_IDS, 0x04 }; +static unsigned char pkcs12PBEWithSha1And40BitRC2CBC[] = { PKCS12_PBE_IDS, 0x05 }; +static unsigned char pkcs12RSAEncryptionWith128BitRC4[] = + { PKCS12_ENVELOPING_IDS, 0x01 }; +static unsigned char pkcs12RSAEncryptionWith40BitRC4[] = + { PKCS12_ENVELOPING_IDS, 0x02 }; +static unsigned char pkcs12RSAEncryptionWithTripleDES[] = + { PKCS12_ENVELOPING_IDS, 0x03 }; +static unsigned char pkcs12RSASignatureWithSHA1Digest[] = + { PKCS12_SIGNATURE_IDS, 0x01 }; +static unsigned char ansix9DSASignature[] = { ANSI_X9_ALGORITHM, 0x01 }; +static unsigned char ansix9DSASignaturewithSHA1Digest[] = + { ANSI_X9_ALGORITHM, 0x03 }; +static unsigned char bogusDSASignaturewithSHA1Digest[] = + { ALGORITHM, 0x1b }; + +/* verisign OIDs */ +static unsigned char verisignUserNotices[] = { VERISIGN, 1, 7, 1, 1 }; + +/* pkix OIDs */ +static unsigned char pkixCPSPointerQualifier[] = { PKIX_POLICY_QUALIFIERS, 1 }; +static unsigned char pkixUserNoticeQualifier[] = { PKIX_POLICY_QUALIFIERS, 2 }; + +static unsigned char pkixOCSP[] = { PKIX_OCSP }; +static unsigned char pkixOCSPBasicResponse[] = { PKIX_OCSP, 1 }; +static unsigned char pkixOCSPNonce[] = { PKIX_OCSP, 2 }; +static unsigned char pkixOCSPCRL[] = { PKIX_OCSP, 3 }; +static unsigned char pkixOCSPResponse[] = { PKIX_OCSP, 4 }; +static unsigned char pkixOCSPNoCheck[] = { PKIX_OCSP, 5 }; +static unsigned char pkixOCSPArchiveCutoff[] = { PKIX_OCSP, 6 }; +static unsigned char pkixOCSPServiceLocator[] = { PKIX_OCSP, 7 }; + +static unsigned char pkixRegCtrlRegToken[] = { PKIX_ID_REGCTRL, 1}; +static unsigned char pkixRegCtrlAuthenticator[] = { PKIX_ID_REGCTRL, 2}; +static unsigned char pkixRegCtrlPKIPubInfo[] = { PKIX_ID_REGCTRL, 3}; +static unsigned char pkixRegCtrlPKIArchOptions[] = { PKIX_ID_REGCTRL, 4}; +static unsigned char pkixRegCtrlOldCertID[] = { PKIX_ID_REGCTRL, 5}; +static unsigned char pkixRegCtrlProtEncKey[] = { PKIX_ID_REGCTRL, 6}; +static unsigned char pkixRegInfoUTF8Pairs[] = { PKIX_ID_REGINFO, 1}; +static unsigned char pkixRegInfoCertReq[] = { PKIX_ID_REGINFO, 2}; + +static unsigned char pkixExtendedKeyUsageServerAuth[] = + { PKIX_KEY_USAGE, 1 }; +static unsigned char pkixExtendedKeyUsageClientAuth[] = + { PKIX_KEY_USAGE, 2 }; +static unsigned char pkixExtendedKeyUsageCodeSign[] = + { PKIX_KEY_USAGE, 3 }; +static unsigned char pkixExtendedKeyUsageEMailProtect[] = + { PKIX_KEY_USAGE, 4 }; +static unsigned char pkixExtendedKeyUsageTimeStamp[] = + { PKIX_KEY_USAGE, 8 }; +static unsigned char pkixOCSPResponderExtendedKeyUsage[] = + { PKIX_KEY_USAGE, 9 }; + +/* OIDs for Netscape defined algorithms */ +static unsigned char netscapeSMimeKEA[] = { NETSCAPE_ALGS, 0x01 }; + +/* pkcs 12 version 1.0 ids */ +static unsigned char pkcs12V2PBEWithSha1And128BitRC4[] = { PKCS12_V2_PBE_IDS, 0x01 }; +static unsigned char pkcs12V2PBEWithSha1And40BitRC4[] = { PKCS12_V2_PBE_IDS, 0x02 }; +static unsigned char pkcs12V2PBEWithSha1And3KeyTripleDEScbc[] = { PKCS12_V2_PBE_IDS, 0x03 }; +static unsigned char pkcs12V2PBEWithSha1And2KeyTripleDEScbc[] = { PKCS12_V2_PBE_IDS, 0x04 }; +static unsigned char pkcs12V2PBEWithSha1And128BitRC2cbc[] = { PKCS12_V2_PBE_IDS, 0x05 }; +static unsigned char pkcs12V2PBEWithSha1And40BitRC2cbc[] = { PKCS12_V2_PBE_IDS, 0x06 }; + +static unsigned char pkcs12SafeContentsID[] = {PKCS12_BAG_IDS, 0x04 }; +static unsigned char pkcs12PKCS8ShroudedKeyBagID[] = { PKCS12_BAG_IDS, 0x05 }; + +static unsigned char pkcs12V1KeyBag[] = { PKCS12_V1_BAG_IDS, 0x01 }; +static unsigned char pkcs12V1PKCS8ShroudedKeyBag[] = { PKCS12_V1_BAG_IDS, 0x02 }; +static unsigned char pkcs12V1CertBag[] = { PKCS12_V1_BAG_IDS, 0x03 }; +static unsigned char pkcs12V1CRLBag[] = { PKCS12_V1_BAG_IDS, 0x04 }; +static unsigned char pkcs12V1SecretBag[] = { PKCS12_V1_BAG_IDS, 0x05 }; +static unsigned char pkcs12V1SafeContentsBag[] = { PKCS12_V1_BAG_IDS, 0x06 }; + +static unsigned char pkcs9X509Certificate[] = { PKCS9_CERT_TYPES, 1 }; +static unsigned char pkcs9SDSICertificate[] = { PKCS9_CERT_TYPES, 2 }; +static unsigned char pkcs9X509CRL[] = { PKCS9_CRL_TYPES, 1 }; +static unsigned char pkcs9FriendlyName[] = { PKCS9, 20 }; +static unsigned char pkcs9LocalKeyID[] = { PKCS9, 21 }; +static unsigned char pkcs12KeyUsageAttr[] = { 2, 5, 29, 15 }; + +/* Fortezza algorithm OIDs */ +static unsigned char skipjackCBC[] = { FORTEZZA_ALG, 0x04 }; +static unsigned char dhPublicKey[] = { ANSI_X942_ALGORITHM, 0x1 }; + +/* Netscape other name types */ +static unsigned char netscapeNickname[] = { NETSCAPE_NAME_COMPONENTS, 0x01}; + +/* OIDs needed for cert server */ +static unsigned char netscapeRecoveryRequest[] = + { NETSCAPE_CERT_SERVER_CRMF, 0x01 }; + +/* + * NOTE: the order of these entries must mach the SECOidTag enum in secoidt.h! + */ +static SECOidData oids[] = { + { { siDEROID, NULL, 0 }, + SEC_OID_UNKNOWN, + "Unknown OID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, md2, sizeof(md2) }, + SEC_OID_MD2, + "MD2", CKM_MD2, INVALID_CERT_EXTENSION }, + { { siDEROID, md4, sizeof(md4) }, + SEC_OID_MD4, + "MD4", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, md5, sizeof(md5) }, + SEC_OID_MD5, + "MD5", CKM_MD5, INVALID_CERT_EXTENSION }, + { { siDEROID, sha1, sizeof(sha1) }, + SEC_OID_SHA1, + "SHA-1", CKM_SHA_1, INVALID_CERT_EXTENSION }, + { { siDEROID, rc2cbc, sizeof(rc2cbc) }, + SEC_OID_RC2_CBC, + "RC2-CBC", CKM_RC2_CBC, INVALID_CERT_EXTENSION }, + { { siDEROID, rc4, sizeof(rc4) }, + SEC_OID_RC4, + "RC4", CKM_RC4, INVALID_CERT_EXTENSION }, + { { siDEROID, desede3cbc, sizeof(desede3cbc) }, + SEC_OID_DES_EDE3_CBC, + "DES-EDE3-CBC", CKM_DES3_CBC, INVALID_CERT_EXTENSION }, + { { siDEROID, rc5cbcpad, sizeof(rc5cbcpad) }, + SEC_OID_RC5_CBC_PAD, + "RC5-CBCPad", CKM_RC5_CBC, INVALID_CERT_EXTENSION }, + { { siDEROID, desecb, sizeof(desecb) }, + SEC_OID_DES_ECB, + "DES-ECB", CKM_DES_ECB, INVALID_CERT_EXTENSION }, + { { siDEROID, descbc, sizeof(descbc) }, + SEC_OID_DES_CBC, + "DES-CBC", CKM_DES_CBC, INVALID_CERT_EXTENSION }, + { { siDEROID, desofb, sizeof(desofb) }, + SEC_OID_DES_OFB, + "DES-OFB", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, descfb, sizeof(descfb) }, + SEC_OID_DES_CFB, + "DES-CFB", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, desmac, sizeof(desmac) }, + SEC_OID_DES_MAC, + "DES-MAC", CKM_DES_MAC, INVALID_CERT_EXTENSION }, + { { siDEROID, desede, sizeof(desede) }, + SEC_OID_DES_EDE, + "DES-EDE", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, isoSHAWithRSASignature, sizeof(isoSHAWithRSASignature) }, + SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE, + "ISO SHA with RSA Signature", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs1RSAEncryption, sizeof(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. + */ + { { siDEROID, pkcs1MD2WithRSAEncryption, sizeof(pkcs1MD2WithRSAEncryption) }, + SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION, + "PKCS #1 MD2 With RSA Encryption", CKM_MD2_RSA_PKCS, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs1MD4WithRSAEncryption, sizeof(pkcs1MD4WithRSAEncryption) }, + SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION, + "PKCS #1 MD4 With RSA Encryption", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs1MD5WithRSAEncryption, sizeof(pkcs1MD5WithRSAEncryption) }, + SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION, + "PKCS #1 MD5 With RSA Encryption", CKM_MD5_RSA_PKCS, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs1SHA1WithRSAEncryption, sizeof(pkcs1SHA1WithRSAEncryption) }, + SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION, + "PKCS #1 SHA-1 With RSA Encryption", CKM_SHA1_RSA_PKCS, + INVALID_CERT_EXTENSION }, + + { { siDEROID, pkcs5PbeWithMD2AndDEScbc, sizeof(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 }, + { { siDEROID, pkcs5PbeWithMD5AndDEScbc, sizeof(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 }, + { { siDEROID, pkcs5PbeWithSha1AndDEScbc, + sizeof(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 }, + { { siDEROID, pkcs7, sizeof(pkcs7) }, + SEC_OID_PKCS7, + "PKCS #7", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs7Data, sizeof(pkcs7Data) }, + SEC_OID_PKCS7_DATA, + "PKCS #7 Data", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs7SignedData, sizeof(pkcs7SignedData) }, + SEC_OID_PKCS7_SIGNED_DATA, + "PKCS #7 Signed Data", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs7EnvelopedData, sizeof(pkcs7EnvelopedData) }, + SEC_OID_PKCS7_ENVELOPED_DATA, + "PKCS #7 Enveloped Data", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs7SignedEnvelopedData, sizeof(pkcs7SignedEnvelopedData) }, + SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA, + "PKCS #7 Signed And Enveloped Data", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs7DigestedData, sizeof(pkcs7DigestedData) }, + SEC_OID_PKCS7_DIGESTED_DATA, + "PKCS #7 Digested Data", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs7EncryptedData, sizeof(pkcs7EncryptedData) }, + SEC_OID_PKCS7_ENCRYPTED_DATA, + "PKCS #7 Encrypted Data", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs9EmailAddress, sizeof(pkcs9EmailAddress) }, + SEC_OID_PKCS9_EMAIL_ADDRESS, + "PKCS #9 Email Address", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs9UnstructuredName, sizeof(pkcs9UnstructuredName) }, + SEC_OID_PKCS9_UNSTRUCTURED_NAME, + "PKCS #9 Unstructured Name", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs9ContentType, sizeof(pkcs9ContentType) }, + SEC_OID_PKCS9_CONTENT_TYPE, + "PKCS #9 Content Type", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs9MessageDigest, sizeof(pkcs9MessageDigest) }, + SEC_OID_PKCS9_MESSAGE_DIGEST, + "PKCS #9 Message Digest", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs9SigningTime, sizeof(pkcs9SigningTime) }, + SEC_OID_PKCS9_SIGNING_TIME, + "PKCS #9 Signing Time", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs9CounterSignature, sizeof(pkcs9CounterSignature) }, + SEC_OID_PKCS9_COUNTER_SIGNATURE, + "PKCS #9 Counter Signature", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs9ChallengePassword, sizeof(pkcs9ChallengePassword) }, + SEC_OID_PKCS9_CHALLENGE_PASSWORD, + "PKCS #9 Challenge Password", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs9UnstructuredAddress, sizeof(pkcs9UnstructuredAddress) }, + SEC_OID_PKCS9_UNSTRUCTURED_ADDRESS, + "PKCS #9 Unstructured Address", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs9ExtendedCertificateAttributes, + sizeof(pkcs9ExtendedCertificateAttributes) }, + SEC_OID_PKCS9_EXTENDED_CERTIFICATE_ATTRIBUTES, + "PKCS #9 Extended Certificate Attributes", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs9SMIMECapabilities, + sizeof(pkcs9SMIMECapabilities) }, + SEC_OID_PKCS9_SMIME_CAPABILITIES, + "PKCS #9 S/MIME Capabilities", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, x520CommonName, + sizeof(x520CommonName) }, + SEC_OID_AVA_COMMON_NAME, + "X520 Common Name", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, x520CountryName, + sizeof(x520CountryName) }, + SEC_OID_AVA_COUNTRY_NAME, + "X520 Country Name", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, x520LocalityName, + sizeof(x520LocalityName) }, + SEC_OID_AVA_LOCALITY, + "X520 Locality Name", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, x520StateOrProvinceName, + sizeof(x520StateOrProvinceName) }, + SEC_OID_AVA_STATE_OR_PROVINCE, + "X520 State Or Province Name", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, x520OrgName, + sizeof(x520OrgName) }, + SEC_OID_AVA_ORGANIZATION_NAME, + "X520 Organization Name", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, x520OrgUnitName, + sizeof(x520OrgUnitName) }, + SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, + "X520 Organizational Unit Name", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, x520DnQualifier, + sizeof(x520DnQualifier) }, + SEC_OID_AVA_DN_QUALIFIER, + "X520 DN Qualifier", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, rfc2247DomainComponent, + sizeof(rfc2247DomainComponent), }, + SEC_OID_AVA_DC, + "RFC 2247 Domain Component", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + + { { siDEROID, nsTypeGIF, + sizeof(nsTypeGIF) }, + SEC_OID_NS_TYPE_GIF, + "GIF", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, nsTypeJPEG, + sizeof(nsTypeJPEG) }, + SEC_OID_NS_TYPE_JPEG, + "JPEG", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, nsTypeURL, + sizeof(nsTypeURL) }, + SEC_OID_NS_TYPE_URL, + "URL", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, nsTypeHTML, + sizeof(nsTypeHTML) }, + SEC_OID_NS_TYPE_HTML, + "HTML", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, nsTypeCertSeq, + sizeof(nsTypeCertSeq) }, + SEC_OID_NS_TYPE_CERT_SEQUENCE, + "Certificate Sequence", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, missiCertKEADSSOld, sizeof(missiCertKEADSSOld) }, + SEC_OID_MISSI_KEA_DSS_OLD, "MISSI KEA and DSS Algorithm (Old)", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION}, + { { siDEROID, missiCertDSSOld, sizeof(missiCertDSSOld) }, + SEC_OID_MISSI_DSS_OLD, "MISSI DSS Algorithm (Old)", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, missiCertKEADSS, sizeof(missiCertKEADSS) }, + SEC_OID_MISSI_KEA_DSS, "MISSI KEA and DSS Algorithm", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, missiCertDSS, sizeof(missiCertDSS) }, + SEC_OID_MISSI_DSS, "MISSI DSS Algorithm", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, missiCertKEA, sizeof(missiCertKEA) }, + SEC_OID_MISSI_KEA, "MISSI KEA Algorithm", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, missiCertAltKEA, sizeof(missiCertAltKEA) }, + SEC_OID_MISSI_ALT_KEA, "MISSI Alternate KEA Algorithm", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + + /* Netscape private extensions */ + { { siDEROID, nsCertExtNetscapeOK, + sizeof(nsCertExtNetscapeOK) }, + SEC_OID_NS_CERT_EXT_NETSCAPE_OK, + "Netscape says this cert is OK", + CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsCertExtIssuerLogo, + sizeof(nsCertExtIssuerLogo) }, + SEC_OID_NS_CERT_EXT_ISSUER_LOGO, + "Certificate Issuer Logo", + CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsCertExtSubjectLogo, + sizeof(nsCertExtSubjectLogo) }, + SEC_OID_NS_CERT_EXT_SUBJECT_LOGO, + "Certificate Subject Logo", + CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsExtCertType, + sizeof(nsExtCertType) }, + SEC_OID_NS_CERT_EXT_CERT_TYPE, + "Certificate Type", + CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsExtBaseURL, + sizeof(nsExtBaseURL) }, + SEC_OID_NS_CERT_EXT_BASE_URL, + "Certificate Extension Base URL", + CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsExtRevocationURL, + sizeof(nsExtRevocationURL) }, + SEC_OID_NS_CERT_EXT_REVOCATION_URL, + "Certificate Revocation URL", + CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsExtCARevocationURL, + sizeof(nsExtCARevocationURL) }, + SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL, + "Certificate Authority Revocation URL", + CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsExtCACRLURL, + sizeof(nsExtCACRLURL) }, + SEC_OID_NS_CERT_EXT_CA_CRL_URL, + "Certificate Authority CRL Download URL", + CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsExtCACertURL, + sizeof(nsExtCACertURL) }, + SEC_OID_NS_CERT_EXT_CA_CERT_URL, + "Certificate Authority Certificate Download URL", + CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsExtCertRenewalURL, + sizeof(nsExtCertRenewalURL) }, + SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL, + "Certificate Renewal URL", CKM_INVALID_MECHANISM, + SUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsExtCAPolicyURL, + sizeof(nsExtCAPolicyURL) }, + SEC_OID_NS_CERT_EXT_CA_POLICY_URL, + "Certificate Authority Policy URL", + CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsExtHomepageURL, + sizeof(nsExtHomepageURL) }, + SEC_OID_NS_CERT_EXT_HOMEPAGE_URL, + "Certificate Homepage URL", CKM_INVALID_MECHANISM, + UNSUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsExtEntityLogo, + sizeof(nsExtEntityLogo) }, + SEC_OID_NS_CERT_EXT_ENTITY_LOGO, + "Certificate Entity Logo", CKM_INVALID_MECHANISM, + UNSUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsExtUserPicture, + sizeof(nsExtUserPicture) }, + SEC_OID_NS_CERT_EXT_USER_PICTURE, + "Certificate User Picture", CKM_INVALID_MECHANISM, + UNSUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsExtSSLServerName, + sizeof(nsExtSSLServerName) }, + SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME, + "Certificate SSL Server Name", CKM_INVALID_MECHANISM, + SUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsExtComment, + sizeof(nsExtComment) }, + SEC_OID_NS_CERT_EXT_COMMENT, + "Certificate Comment", CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsExtLostPasswordURL, + sizeof(nsExtLostPasswordURL) }, + SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL, + "Lost Password URL", CKM_INVALID_MECHANISM, + SUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsExtCertRenewalTime, + sizeof(nsExtCertRenewalTime) }, + SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME, + "Certificate Renewal Time", CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION }, + { { siDEROID, nsKeyUsageGovtApproved, + sizeof(nsKeyUsageGovtApproved) }, + SEC_OID_NS_KEY_USAGE_GOVT_APPROVED, + "Strong Crypto Export Approved", + CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION }, + + + /* x.509 v3 certificate extensions */ + { { siDEROID, x509SubjectDirectoryAttr, sizeof(x509SubjectDirectoryAttr) }, + SEC_OID_X509_SUBJECT_DIRECTORY_ATTR, + "Certificate Subject Directory Attributes", + CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION}, + { { siDEROID, x509SubjectKeyID, sizeof(x509SubjectKeyID) }, + SEC_OID_X509_SUBJECT_KEY_ID, "Certificate Subject Key ID", + CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION }, + { { siDEROID, x509KeyUsage, sizeof(x509KeyUsage) }, + SEC_OID_X509_KEY_USAGE, "Certificate Key Usage", + CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION }, + { { siDEROID, x509PrivateKeyUsagePeriod, + sizeof(x509PrivateKeyUsagePeriod) }, + SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD, + "Certificate Private Key Usage Period", + CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION }, + { { siDEROID, x509SubjectAltName, sizeof(x509SubjectAltName) }, + SEC_OID_X509_SUBJECT_ALT_NAME, "Certificate Subject Alt Name", + CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION }, + { { siDEROID, x509IssuerAltName, sizeof(x509IssuerAltName) }, + SEC_OID_X509_ISSUER_ALT_NAME, "Certificate Issuer Alt Name", + CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION }, + { { siDEROID, x509BasicConstraints, sizeof(x509BasicConstraints) }, + SEC_OID_X509_BASIC_CONSTRAINTS, "Certificate Basic Constraints", + CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION }, + { { siDEROID, x509NameConstraints, sizeof(x509NameConstraints) }, + SEC_OID_X509_NAME_CONSTRAINTS, "Certificate Name Constraints", + CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION }, + { { siDEROID, x509CRLDistPoints, sizeof(x509CRLDistPoints) }, + SEC_OID_X509_CRL_DIST_POINTS, "CRL Distribution Points", + CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION }, + { { siDEROID, x509CertificatePolicies, sizeof(x509CertificatePolicies) }, + SEC_OID_X509_CERTIFICATE_POLICIES, + "Certificate Policies", + CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION }, + { { siDEROID, x509PolicyMappings, sizeof(x509PolicyMappings) }, + SEC_OID_X509_POLICY_MAPPINGS, "Certificate Policy Mappings", + CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION }, + { { siDEROID, x509PolicyConstraints, sizeof(x509PolicyConstraints) }, + SEC_OID_X509_POLICY_CONSTRAINTS, "Certificate Policy Constraints", + CKM_INVALID_MECHANISM, UNSUPPORTED_CERT_EXTENSION }, + { { siDEROID, x509AuthKeyID, sizeof(x509AuthKeyID) }, + SEC_OID_X509_AUTH_KEY_ID, "Certificate Authority Key Identifier", + CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION }, + { { siDEROID, x509ExtKeyUsage, sizeof(x509ExtKeyUsage) }, + SEC_OID_X509_EXT_KEY_USAGE, "Extended Key Usage", + CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION }, + { { siDEROID, x509AuthInfoAccess, sizeof(x509AuthInfoAccess) }, + SEC_OID_X509_AUTH_INFO_ACCESS, "Authority Information Access", + CKM_INVALID_MECHANISM, SUPPORTED_CERT_EXTENSION }, + + /* x.509 v3 CRL extensions */ + { { siDEROID, x509CrlNumber, sizeof(x509CrlNumber) }, + SEC_OID_X509_CRL_NUMBER, "CRL Number", CKM_INVALID_MECHANISM, + SUPPORTED_CERT_EXTENSION }, + { { siDEROID, x509ReasonCode, sizeof(x509ReasonCode) }, + SEC_OID_X509_REASON_CODE, "CRL reason code", CKM_INVALID_MECHANISM, + SUPPORTED_CERT_EXTENSION }, + { { siDEROID, x509InvalidDate, sizeof(x509InvalidDate) }, + SEC_OID_X509_INVALID_DATE, "Invalid Date", CKM_INVALID_MECHANISM, + SUPPORTED_CERT_EXTENSION }, + + { { siDEROID, x500RSAEncryption, sizeof(x500RSAEncryption) }, + SEC_OID_X500_RSA_ENCRYPTION, + "X500 RSA Encryption", CKM_RSA_X_509, INVALID_CERT_EXTENSION }, + + /* added for alg 1485 */ + { { siDEROID, rfc1274Uid, + sizeof(rfc1274Uid) }, + SEC_OID_RFC1274_UID, + "RFC1274 User Id", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, rfc1274Mail, + sizeof(rfc1274Uid) }, + SEC_OID_RFC1274_MAIL, + "RFC1274 E-mail Address", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + + /* pkcs 12 additions */ + { { siDEROID, pkcs12, sizeof(pkcs12) }, + SEC_OID_PKCS12, + "PKCS #12", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12ModeIDs, sizeof(pkcs12ModeIDs) }, + SEC_OID_PKCS12_MODE_IDS, + "PKCS #12 Mode IDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12ESPVKIDs, sizeof(pkcs12ESPVKIDs) }, + SEC_OID_PKCS12_ESPVK_IDS, + "PKCS #12 ESPVK IDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12BagIDs, sizeof(pkcs12BagIDs) }, + SEC_OID_PKCS12_BAG_IDS, + "PKCS #12 Bag IDs", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12CertBagIDs, sizeof(pkcs12CertBagIDs) }, + SEC_OID_PKCS12_CERT_BAG_IDS, + "PKCS #12 Cert Bag IDs", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12OIDs, sizeof(pkcs12OIDs) }, + SEC_OID_PKCS12_OIDS, + "PKCS #12 OIDs", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12PBEIDs, sizeof(pkcs12PBEIDs) }, + SEC_OID_PKCS12_PBE_IDS, + "PKCS #12 PBE IDs", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12SignatureIDs, sizeof(pkcs12SignatureIDs) }, + SEC_OID_PKCS12_SIGNATURE_IDS, + "PKCS #12 Signature IDs", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12EnvelopingIDs, sizeof(pkcs12EnvelopingIDs) }, + SEC_OID_PKCS12_ENVELOPING_IDS, + "PKCS #12 Enveloping IDs", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12PKCS8KeyShrouding, + sizeof(pkcs12PKCS8KeyShrouding) }, + SEC_OID_PKCS12_PKCS8_KEY_SHROUDING, + "PKCS #12 Key Shrouding", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12KeyBagID, + sizeof(pkcs12KeyBagID) }, + SEC_OID_PKCS12_KEY_BAG_ID, + "PKCS #12 Key Bag ID", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12CertAndCRLBagID, + sizeof(pkcs12CertAndCRLBagID) }, + SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID, + "PKCS #12 Cert And CRL Bag ID", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12SecretBagID, + sizeof(pkcs12SecretBagID) }, + SEC_OID_PKCS12_SECRET_BAG_ID, + "PKCS #12 Secret Bag ID", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12X509CertCRLBag, + sizeof(pkcs12X509CertCRLBag) }, + SEC_OID_PKCS12_X509_CERT_CRL_BAG, + "PKCS #12 X509 Cert CRL Bag", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12SDSICertBag, + sizeof(pkcs12SDSICertBag) }, + SEC_OID_PKCS12_SDSI_CERT_BAG, + "PKCS #12 SDSI Cert Bag", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12PBEWithSha1And128BitRC4, + sizeof(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 }, + { { siDEROID, pkcs12PBEWithSha1And40BitRC4, + sizeof(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 }, + { { siDEROID, pkcs12PBEWithSha1AndTripleDESCBC, + sizeof(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 }, + { { siDEROID, pkcs12PBEWithSha1And128BitRC2CBC, + sizeof(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 }, + { { siDEROID, pkcs12PBEWithSha1And40BitRC2CBC, + sizeof(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 }, + { { siDEROID, pkcs12RSAEncryptionWith128BitRC4, + sizeof(pkcs12RSAEncryptionWith128BitRC4) }, + SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_128_BIT_RC4, + "PKCS #12 RSA Encryption with 128 Bit RC4", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12RSAEncryptionWith40BitRC4, + sizeof(pkcs12RSAEncryptionWith40BitRC4) }, + SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_40_BIT_RC4, + "PKCS #12 RSA Encryption with 40 Bit RC4", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12RSAEncryptionWithTripleDES, + sizeof(pkcs12RSAEncryptionWithTripleDES) }, + SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_TRIPLE_DES, + "PKCS #12 RSA Encryption with Triple DES", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12RSASignatureWithSHA1Digest, + sizeof(pkcs12RSASignatureWithSHA1Digest) }, + SEC_OID_PKCS12_RSA_SIGNATURE_WITH_SHA1_DIGEST, + "PKCS #12 RSA Encryption with Triple DES", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + + /* DSA signatures */ + { { siDEROID, ansix9DSASignature, sizeof(ansix9DSASignature) }, + SEC_OID_ANSIX9_DSA_SIGNATURE, + "ANSI X9.57 DSA Signature", CKM_DSA, + INVALID_CERT_EXTENSION }, + { { siDEROID, ansix9DSASignaturewithSHA1Digest, + sizeof(ansix9DSASignaturewithSHA1Digest) }, + SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST, + "ANSI X9.57 DSA Signature with SHA1 Digest", CKM_DSA_SHA1, + INVALID_CERT_EXTENSION }, + { { siDEROID, bogusDSASignaturewithSHA1Digest, + sizeof(bogusDSASignaturewithSHA1Digest) }, + SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST, + "FORTEZZA DSA Signature with SHA1 Digest", CKM_DSA_SHA1, + INVALID_CERT_EXTENSION }, + + /* verisign oids */ + { { siDEROID, verisignUserNotices, + sizeof(verisignUserNotices) }, + SEC_OID_VERISIGN_USER_NOTICES, + "Verisign User Notices", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + + /* pkix oids */ + { { siDEROID, pkixCPSPointerQualifier, + sizeof(pkixCPSPointerQualifier) }, + SEC_OID_PKIX_CPS_POINTER_QUALIFIER, + "PKIX CPS Pointer Qualifier", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkixUserNoticeQualifier, + sizeof(pkixUserNoticeQualifier) }, + SEC_OID_PKIX_USER_NOTICE_QUALIFIER, + "PKIX User Notice Qualifier", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + + { { siDEROID, pkixOCSP, sizeof(pkixOCSP), }, + SEC_OID_PKIX_OCSP, + "PKIX Online Certificate Status Protocol", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkixOCSPBasicResponse, sizeof(pkixOCSPBasicResponse), }, + SEC_OID_PKIX_OCSP_BASIC_RESPONSE, + "OCSP Basic Response", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkixOCSPNonce, sizeof(pkixOCSPNonce), }, + SEC_OID_PKIX_OCSP_NONCE, + "OCSP Nonce Extension", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkixOCSPCRL, sizeof(pkixOCSPCRL), }, + SEC_OID_PKIX_OCSP_CRL, + "OCSP CRL Reference Extension", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkixOCSPResponse, sizeof(pkixOCSPResponse), }, + SEC_OID_PKIX_OCSP_RESPONSE, + "OCSP Response Types Extension", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkixOCSPNoCheck, sizeof(pkixOCSPNoCheck) }, + SEC_OID_PKIX_OCSP_NO_CHECK, + "OCSP No Check Extension", CKM_INVALID_MECHANISM, + SUPPORTED_CERT_EXTENSION }, + { { siDEROID, pkixOCSPArchiveCutoff, sizeof(pkixOCSPArchiveCutoff) }, + SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF, + "OCSP Archive Cutoff Extension", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkixOCSPServiceLocator, sizeof(pkixOCSPServiceLocator) }, + SEC_OID_PKIX_OCSP_SERVICE_LOCATOR, + "OCSP Service Locator Extension", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + + { { siDEROID, pkixRegCtrlRegToken, + sizeof (pkixRegCtrlRegToken) }, + SEC_OID_PKIX_REGCTRL_REGTOKEN, + "PKIX CRMF Registration Control, Registration Token", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkixRegCtrlAuthenticator, + sizeof (pkixRegCtrlAuthenticator) }, + SEC_OID_PKIX_REGCTRL_AUTHENTICATOR, + "PKIX CRMF Registration Control, Registration Authenticator", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION }, + { { siDEROID, pkixRegCtrlPKIPubInfo, + sizeof (pkixRegCtrlPKIPubInfo) }, + SEC_OID_PKIX_REGCTRL_PKIPUBINFO, + "PKIX CRMF Registration Control, PKI Publication Info", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION}, + { { siDEROID, pkixRegCtrlPKIArchOptions, + sizeof (pkixRegCtrlPKIArchOptions) }, + SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS, + "PKIX CRMF Registration Control, PKI Archive Options", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION}, + { { siDEROID, pkixRegCtrlOldCertID, + sizeof (pkixRegCtrlOldCertID) }, + SEC_OID_PKIX_REGCTRL_OLD_CERT_ID, + "PKIX CRMF Registration Control, Old Certificate ID", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION}, + { { siDEROID, pkixRegCtrlProtEncKey, + sizeof (pkixRegCtrlProtEncKey) }, + SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY, + "PKIX CRMF Registration Control, Protocol Encryption Key", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION}, + { { siDEROID, pkixRegInfoUTF8Pairs, + sizeof (pkixRegInfoUTF8Pairs) }, + SEC_OID_PKIX_REGINFO_UTF8_PAIRS, + "PKIX CRMF Registration Info, UTF8 Pairs", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION}, + { { siDEROID, pkixRegInfoCertReq, + sizeof (pkixRegInfoCertReq) }, + SEC_OID_PKIX_REGINFO_CERT_REQUEST, + "PKIX CRMF Registration Info, Certificate Request", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION}, + { { siDEROID, pkixExtendedKeyUsageServerAuth, + sizeof (pkixExtendedKeyUsageServerAuth) }, + SEC_OID_EXT_KEY_USAGE_SERVER_AUTH, + "TLS Web Server Authentication Certificate", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION}, + { { siDEROID, pkixExtendedKeyUsageClientAuth, + sizeof (pkixExtendedKeyUsageClientAuth) }, + SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH, + "TLS Web Client Authentication Certificate", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION}, + { { siDEROID, pkixExtendedKeyUsageCodeSign, + sizeof (pkixExtendedKeyUsageCodeSign) }, + SEC_OID_EXT_KEY_USAGE_CODE_SIGN, + "Code Signing Certificate", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION}, + { { siDEROID, pkixExtendedKeyUsageEMailProtect, + sizeof (pkixExtendedKeyUsageEMailProtect) }, + SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT, + "E-Mail Protection Certificate", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION}, + { { siDEROID, pkixExtendedKeyUsageTimeStamp, + sizeof (pkixExtendedKeyUsageTimeStamp) }, + SEC_OID_EXT_KEY_USAGE_TIME_STAMP, + "Time Stamping Certifcate", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION}, + { { siDEROID, pkixOCSPResponderExtendedKeyUsage, + sizeof (pkixOCSPResponderExtendedKeyUsage) }, + SEC_OID_OCSP_RESPONDER, + "OCSP Responder Certificate", + CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION}, + + /* Netscape Algorithm OIDs */ + + { { siDEROID, netscapeSMimeKEA, + sizeof(netscapeSMimeKEA) }, + SEC_OID_NETSCAPE_SMIME_KEA, + "Netscape S/MIME KEA", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + + /* Skipjack OID -- ### mwelch temporary */ + { { siDEROID, skipjackCBC, + sizeof(skipjackCBC) }, + SEC_OID_FORTEZZA_SKIPJACK, + "Skipjack CBC64", CKM_SKIPJACK_CBC64, + INVALID_CERT_EXTENSION }, + + /* pkcs12 v2 oids */ + { { siDEROID, pkcs12V2PBEWithSha1And128BitRC4, + sizeof(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 }, + { { siDEROID, pkcs12V2PBEWithSha1And40BitRC4, + sizeof(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 }, + { { siDEROID, pkcs12V2PBEWithSha1And3KeyTripleDEScbc, + sizeof(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 }, + { { siDEROID, pkcs12V2PBEWithSha1And2KeyTripleDEScbc, + sizeof(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 }, + { { siDEROID, pkcs12V2PBEWithSha1And128BitRC2cbc, + sizeof(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 }, + { { siDEROID, pkcs12V2PBEWithSha1And40BitRC2cbc, + sizeof(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 }, + { { siDEROID, pkcs12SafeContentsID, + sizeof(pkcs12SafeContentsID) }, + SEC_OID_PKCS12_SAFE_CONTENTS_ID, + "PKCS #12 Safe Contents ID", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12PKCS8ShroudedKeyBagID, + sizeof(pkcs12PKCS8ShroudedKeyBagID) }, + SEC_OID_PKCS12_PKCS8_SHROUDED_KEY_BAG_ID, + "PKCS #12 Safe Contents ID", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12V1KeyBag, + sizeof(pkcs12V1KeyBag) }, + SEC_OID_PKCS12_V1_KEY_BAG_ID, + "PKCS #12 V1 Key Bag", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12V1PKCS8ShroudedKeyBag, + sizeof(pkcs12V1PKCS8ShroudedKeyBag) }, + SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID, + "PKCS #12 V1 PKCS8 Shrouded Key Bag", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12V1CertBag, + sizeof(pkcs12V1CertBag) }, + SEC_OID_PKCS12_V1_CERT_BAG_ID, + "PKCS #12 V1 Cert Bag", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12V1CRLBag, + sizeof(pkcs12V1CRLBag) }, + SEC_OID_PKCS12_V1_CRL_BAG_ID, + "PKCS #12 V1 CRL Bag", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12V1SecretBag, + sizeof(pkcs12V1SecretBag) }, + SEC_OID_PKCS12_V1_SECRET_BAG_ID, + "PKCS #12 V1 Secret Bag", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12V1SafeContentsBag, + sizeof(pkcs12V1SafeContentsBag) }, + SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID, + "PKCS #12 V1 Safe Contents Bag", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + + { { siDEROID, pkcs9X509Certificate, + sizeof(pkcs9X509Certificate) }, + SEC_OID_PKCS9_X509_CERT, + "PKCS #9 X509 Certificate", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs9SDSICertificate, + sizeof(pkcs9SDSICertificate) }, + SEC_OID_PKCS9_SDSI_CERT, + "PKCS #9 SDSI Certificate", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs9X509CRL, + sizeof(pkcs9X509CRL) }, + SEC_OID_PKCS9_X509_CRL, + "PKCS #9 X509 CRL", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs9FriendlyName, + sizeof(pkcs9FriendlyName) }, + SEC_OID_PKCS9_FRIENDLY_NAME, + "PKCS #9 Friendly Name", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs9LocalKeyID, + sizeof(pkcs9LocalKeyID) }, + SEC_OID_PKCS9_LOCAL_KEY_ID, + "PKCS #9 Local Key ID", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, pkcs12KeyUsageAttr, + sizeof(pkcs12KeyUsageAttr) }, + SEC_OID_PKCS12_KEY_USAGE, + "PKCS 12 Key Usage", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + { { siDEROID, dhPublicKey, + sizeof(dhPublicKey) }, + SEC_OID_X942_DIFFIE_HELMAN_KEY, + "Diffie-Helman Public Key", CKM_DH_PKCS_DERIVE, + INVALID_CERT_EXTENSION }, + { { siDEROID, netscapeNickname, + sizeof(netscapeNickname) }, + SEC_OID_NETSCAPE_NICKNAME, + "Netscape Nickname", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + + /* Cert Server specific OIDs */ + { { siDEROID, netscapeRecoveryRequest, + sizeof(netscapeRecoveryRequest) }, + SEC_OID_NETSCAPE_RECOVERY_REQUEST, + "Recovery Request OID", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + + { { siDEROID, nsExtAIACertRenewal, + sizeof(nsExtAIACertRenewal) }, + SEC_OID_CERT_RENEWAL_LOCATOR, + "Certificate Renewal Locator OID", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION }, + + { { siDEROID, nsExtCertScopeOfUse, + sizeof(nsExtCertScopeOfUse) }, + SEC_OID_NS_CERT_EXT_SCOPE_OF_USE, + "Certificate Scope-of-Use Extension", CKM_INVALID_MECHANISM, + SUPPORTED_CERT_EXTENSION }, +}; + +/* + * now the dynamic table. The dynamic table gets build at init time. + * and gets modified if the user loads new crypto modules. + */ + +static DB *oid_d_hash = 0; +static SECOidData **secoidDynamicTable = NULL; +static int secoidDynamicTableSize = 0; +static int secoidLastDynamicEntry = 0; +static int secoidLastHashEntry = 0; + +static SECStatus +secoid_DynamicRehash(void) +{ + DBT key; + DBT data; + int rv; + SECOidData *oid; + int i; + int last = secoidLastDynamicEntry; + + if (!oid_d_hash) { + oid_d_hash = dbopen( 0, O_RDWR | O_CREAT, 0600, DB_HASH, 0 ); + } + + + if ( !oid_d_hash ) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return(SECFailure); + } + + for ( i = secoidLastHashEntry; i < last; i++ ) { + oid = secoidDynamicTable[i]; + + /* invalid assert ... guarrenteed not to be true */ + /* PORT_Assert ( oid->offset == i ); */ + + key.data = oid->oid.data; + key.size = oid->oid.len; + + data.data = &oid; + data.size = sizeof(oid); + + rv = (* oid_d_hash->put)( oid_d_hash, &key, &data, R_NOOVERWRITE ); + if ( rv ) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return(SECFailure); + } + } + secoidLastHashEntry = last; + return(SECSuccess); +} + +/* + * 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. Worry: what about thread safety here? Global Static data with + * no locks.... (sigh). + */ +static SECStatus +secoid_FindDynamic(DBT *key, DBT *data) { + if (secoidDynamicTable == NULL) { + return SECFailure; + } + if (secoidLastHashEntry != secoidLastDynamicEntry) { + SECStatus rv = secoid_DynamicRehash(); + if ( rv != SECSuccess ) { + return rv; + } + } + return (SECStatus)(* oid_d_hash->get)( oid_d_hash, key, data, 0 ); + +} + +static SECOidData * +secoid_FindDynamicByTag(SECOidTag tagnum) +{ + int tagNumDiff; + + if (secoidDynamicTable == NULL) { + return NULL; + } + + if (tagnum < SEC_OID_TOTAL) { + return NULL; + } + + tagNumDiff = tagnum - SEC_OID_TOTAL; + if (tagNumDiff >= secoidLastDynamicEntry) { + return NULL; + } + + return(secoidDynamicTable[tagNumDiff]); +} + +/* + * this routine is definately not thread safe. It is only called out + * of the UI, or at init time. If we want to call it any other time, + * we need to make it thread safe. + */ +SECStatus +SECOID_AddEntry(SECItem *oid, char *description, unsigned long mech) { + SECOidData *oiddp = (SECOidData *)PORT_Alloc(sizeof(SECOidData)); + int last = secoidLastDynamicEntry; + int tableSize = secoidDynamicTableSize; + int next = last++; + SECOidData **newTable = secoidDynamicTable; + SECOidData **oldTable = NULL; + + if (oid == NULL) { + return SECFailure; + } + + /* fill in oid structure */ + if (SECITEM_CopyItem(NULL,&oiddp->oid,oid) != SECSuccess) { + PORT_Free(oiddp); + return SECFailure; + } + oiddp->offset = (SECOidTag)(next + SEC_OID_TOTAL); + /* may we should just reference the copy passed to us? */ + oiddp->desc = PORT_Strdup(description); + oiddp->mechanism = mech; + + + if (last > tableSize) { + int oldTableSize = tableSize; + tableSize += 10; + oldTable = newTable; + newTable = (SECOidData **)PORT_ZAlloc(sizeof(SECOidData *)*tableSize); + if (newTable == NULL) { + PORT_Free(oiddp->oid.data); + PORT_Free(oiddp); + return SECFailure; + } + PORT_Memcpy(newTable,oldTable,sizeof(SECOidData *)*oldTableSize); + PORT_Free(oldTable); + } + + newTable[next] = oiddp; + secoidDynamicTable = newTable; + secoidDynamicTableSize = tableSize; + secoidLastDynamicEntry= last; + return SECSuccess; +} + + +/* normal static table processing */ +static DB *oidhash = NULL; +static DB *oidmechhash = NULL; + +static SECStatus +InitOIDHash(void) +{ + DBT key; + DBT data; + int rv; + SECOidData *oid; + int i; + + oidhash = dbopen( 0, O_RDWR | O_CREAT, 0600, DB_HASH, 0 ); + oidmechhash = dbopen( 0, O_RDWR | O_CREAT, 0600, DB_HASH, 0 ); + + 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 ); + + key.data = oid->oid.data; + key.size = oid->oid.len; + + data.data = &oid; + data.size = sizeof(oid); + + rv = (* oidhash->put)( oidhash, &key, &data, R_NOOVERWRITE ); + if ( rv ) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + PORT_Assert(0); /*This function should never fail. */ + return(SECFailure); + } + + if ( oid->mechanism != CKM_INVALID_MECHANISM ) { + key.data = &oid->mechanism; + key.size = sizeof(oid->mechanism); + + rv = (* oidmechhash->put)( oidmechhash, &key, &data, R_NOOVERWRITE); + /* Only error out if the error value returned is not + * RET_SPECIAL, ie the mechanism already has a registered + * OID. + */ + if ( rv && rv != RET_SPECIAL) { + 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) +{ + DBT key; + DBT data; + SECOidData *ret; + int rv; + + if ( !oidhash ) { + rv = InitOIDHash(); + if ( rv != SECSuccess ) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return NULL; + } + } + key.data = &mechanism; + key.size = sizeof(mechanism); + + rv = (* oidmechhash->get)( oidmechhash, &key, &data, 0 ); + if ( rv || ( data.size != sizeof(unsigned long) ) ) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return NULL; + } + PORT_Memcpy(&ret, data.data, data.size); + + return (ret); +} + +SECOidData * +SECOID_FindOID(SECItem *oid) +{ + DBT key; + DBT data; + SECOidData *ret; + int rv; + + if ( !oidhash ) { + rv = InitOIDHash(); + if ( rv != SECSuccess ) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return NULL; + } + } + + key.data = oid->data; + key.size = oid->len; + + rv = (* oidhash->get)( oidhash, &key, &data, 0 ); + if ( rv || ( data.size != sizeof(SECOidData*) ) ) { + rv = secoid_FindDynamic(&key, &data); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return(0); + } + } + + PORT_Memcpy(&ret, data.data, data.size); + + return(ret); +} + +SECOidTag +SECOID_FindOIDTag(SECItem *oid) +{ + SECOidData *oiddata; + + oiddata = SECOID_FindOID (oid); + if (oiddata == NULL) + return SEC_OID_UNKNOWN; + + return oiddata->offset; +} + +SECOidData * +SECOID_FindOIDByTag(SECOidTag tagnum) +{ + + if (tagnum >= SEC_OID_TOTAL) { + return secoid_FindDynamicByTag(tagnum); + } + + PORT_Assert((unsigned int)tagnum < (sizeof(oids) / sizeof(SECOidData))); + return(&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) +{ + SECOidData *oidData = SECOID_FindOIDByTag(tagnum); + if (!oidData) + return 0; + else + return oidData->desc; +} diff --git a/security/nss/lib/util/secoid.h b/security/nss/lib/util/secoid.h new file mode 100644 index 000000000..9f8c7b11c --- /dev/null +++ b/security/nss/lib/util/secoid.h @@ -0,0 +1,112 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef _SECOID_H_ +#define _SECOID_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" + +extern const SEC_ASN1Template SECOID_AlgorithmIDTemplate[]; + +SEC_BEGIN_PROTOS + +/* + * OID handling routines + */ +extern SECOidData *SECOID_FindOID(SECItem *oid); +extern SECOidTag SECOID_FindOIDTag(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 defining the algorithm (SEC_OID_*) +** "params" if not NULL, the parameters to go with the algorithm +*/ +extern SECStatus SECOID_SetAlgorithmID(PRArenaPool *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(PRArenaPool *arena, SECAlgorithmID *dest, + SECAlgorithmID *src); + +/* +** Get the SEC_OID_* tag 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 SEC_OID_* tag, return a string describing it. + */ +extern const char *SECOID_FindOIDTagDescription(SECOidTag tagnum); + + +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..51368180f --- /dev/null +++ b/security/nss/lib/util/secoidt.h @@ -0,0 +1,301 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef _SECOIDT_H_ +#define _SECOIDT_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, + SEC_OID_MD2, + SEC_OID_MD4, + SEC_OID_MD5, + SEC_OID_SHA1, + SEC_OID_RC2_CBC, + SEC_OID_RC4, + SEC_OID_DES_EDE3_CBC, + SEC_OID_RC5_CBC_PAD, + SEC_OID_DES_ECB, + SEC_OID_DES_CBC, + SEC_OID_DES_OFB, + SEC_OID_DES_CFB, + SEC_OID_DES_MAC, + SEC_OID_DES_EDE, + SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE, + SEC_OID_PKCS1_RSA_ENCRYPTION, + SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION, + SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION, + SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION, + SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION, + SEC_OID_PKCS5_PBE_WITH_MD2_AND_DES_CBC, + SEC_OID_PKCS5_PBE_WITH_MD5_AND_DES_CBC, + SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC, + SEC_OID_PKCS7, + SEC_OID_PKCS7_DATA, + SEC_OID_PKCS7_SIGNED_DATA, + SEC_OID_PKCS7_ENVELOPED_DATA, + SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA, + SEC_OID_PKCS7_DIGESTED_DATA, + SEC_OID_PKCS7_ENCRYPTED_DATA, + SEC_OID_PKCS9_EMAIL_ADDRESS, + SEC_OID_PKCS9_UNSTRUCTURED_NAME, + SEC_OID_PKCS9_CONTENT_TYPE, + SEC_OID_PKCS9_MESSAGE_DIGEST, + SEC_OID_PKCS9_SIGNING_TIME, + SEC_OID_PKCS9_COUNTER_SIGNATURE, + SEC_OID_PKCS9_CHALLENGE_PASSWORD, + SEC_OID_PKCS9_UNSTRUCTURED_ADDRESS, + SEC_OID_PKCS9_EXTENDED_CERTIFICATE_ATTRIBUTES, + SEC_OID_PKCS9_SMIME_CAPABILITIES, + SEC_OID_AVA_COMMON_NAME, + SEC_OID_AVA_COUNTRY_NAME, + SEC_OID_AVA_LOCALITY, + SEC_OID_AVA_STATE_OR_PROVINCE, + SEC_OID_AVA_ORGANIZATION_NAME, + SEC_OID_AVA_ORGANIZATIONAL_UNIT_NAME, + SEC_OID_AVA_DN_QUALIFIER, + SEC_OID_AVA_DC, + + SEC_OID_NS_TYPE_GIF, + SEC_OID_NS_TYPE_JPEG, + SEC_OID_NS_TYPE_URL, + SEC_OID_NS_TYPE_HTML, + SEC_OID_NS_TYPE_CERT_SEQUENCE, + SEC_OID_MISSI_KEA_DSS_OLD, + SEC_OID_MISSI_DSS_OLD, + SEC_OID_MISSI_KEA_DSS, + SEC_OID_MISSI_DSS, + SEC_OID_MISSI_KEA, + SEC_OID_MISSI_ALT_KEA, + + /* Netscape private certificate extensions */ + SEC_OID_NS_CERT_EXT_NETSCAPE_OK, + SEC_OID_NS_CERT_EXT_ISSUER_LOGO, + SEC_OID_NS_CERT_EXT_SUBJECT_LOGO, + SEC_OID_NS_CERT_EXT_CERT_TYPE, + SEC_OID_NS_CERT_EXT_BASE_URL, + SEC_OID_NS_CERT_EXT_REVOCATION_URL, + SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL, + SEC_OID_NS_CERT_EXT_CA_CRL_URL, + SEC_OID_NS_CERT_EXT_CA_CERT_URL, + SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL, + SEC_OID_NS_CERT_EXT_CA_POLICY_URL, + SEC_OID_NS_CERT_EXT_HOMEPAGE_URL, + SEC_OID_NS_CERT_EXT_ENTITY_LOGO, + SEC_OID_NS_CERT_EXT_USER_PICTURE, + SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME, + SEC_OID_NS_CERT_EXT_COMMENT, + SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL, + SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME, + SEC_OID_NS_KEY_USAGE_GOVT_APPROVED, + + /* x.509 v3 Extensions */ + SEC_OID_X509_SUBJECT_DIRECTORY_ATTR, + SEC_OID_X509_SUBJECT_KEY_ID, + SEC_OID_X509_KEY_USAGE, + SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD, + SEC_OID_X509_SUBJECT_ALT_NAME, + SEC_OID_X509_ISSUER_ALT_NAME, + SEC_OID_X509_BASIC_CONSTRAINTS, + SEC_OID_X509_NAME_CONSTRAINTS, + SEC_OID_X509_CRL_DIST_POINTS, + SEC_OID_X509_CERTIFICATE_POLICIES, + SEC_OID_X509_POLICY_MAPPINGS, + SEC_OID_X509_POLICY_CONSTRAINTS, + SEC_OID_X509_AUTH_KEY_ID, + SEC_OID_X509_EXT_KEY_USAGE, + SEC_OID_X509_AUTH_INFO_ACCESS, + + SEC_OID_X509_CRL_NUMBER, + SEC_OID_X509_REASON_CODE, + SEC_OID_X509_INVALID_DATE, + /* End of x.509 v3 Extensions */ + + SEC_OID_X500_RSA_ENCRYPTION, + + /* alg 1485 additions */ + SEC_OID_RFC1274_UID, + SEC_OID_RFC1274_MAIL, + + /* PKCS 12 additions */ + SEC_OID_PKCS12, + SEC_OID_PKCS12_MODE_IDS, + SEC_OID_PKCS12_ESPVK_IDS, + SEC_OID_PKCS12_BAG_IDS, + SEC_OID_PKCS12_CERT_BAG_IDS, + SEC_OID_PKCS12_OIDS, + SEC_OID_PKCS12_PBE_IDS, + SEC_OID_PKCS12_SIGNATURE_IDS, + SEC_OID_PKCS12_ENVELOPING_IDS, + /* SEC_OID_PKCS12_OFFLINE_TRANSPORT_MODE, + SEC_OID_PKCS12_ONLINE_TRANSPORT_MODE, */ + SEC_OID_PKCS12_PKCS8_KEY_SHROUDING, + SEC_OID_PKCS12_KEY_BAG_ID, + SEC_OID_PKCS12_CERT_AND_CRL_BAG_ID, + SEC_OID_PKCS12_SECRET_BAG_ID, + SEC_OID_PKCS12_X509_CERT_CRL_BAG, + SEC_OID_PKCS12_SDSI_CERT_BAG, + SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC4, + SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC4, + SEC_OID_PKCS12_PBE_WITH_SHA1_AND_TRIPLE_DES_CBC, + SEC_OID_PKCS12_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC, + SEC_OID_PKCS12_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC, + SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_128_BIT_RC4, + SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_40_BIT_RC4, + SEC_OID_PKCS12_RSA_ENCRYPTION_WITH_TRIPLE_DES, + SEC_OID_PKCS12_RSA_SIGNATURE_WITH_SHA1_DIGEST, + /* end of PKCS 12 additions */ + + /* DSA signatures */ + SEC_OID_ANSIX9_DSA_SIGNATURE, + SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST, + SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST, + + /* Verisign OIDs */ + SEC_OID_VERISIGN_USER_NOTICES, + + /* PKIX OIDs */ + SEC_OID_PKIX_CPS_POINTER_QUALIFIER, + SEC_OID_PKIX_USER_NOTICE_QUALIFIER, + SEC_OID_PKIX_OCSP, + SEC_OID_PKIX_OCSP_BASIC_RESPONSE, + SEC_OID_PKIX_OCSP_NONCE, + SEC_OID_PKIX_OCSP_CRL, + SEC_OID_PKIX_OCSP_RESPONSE, + SEC_OID_PKIX_OCSP_NO_CHECK, + SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF, + SEC_OID_PKIX_OCSP_SERVICE_LOCATOR, + SEC_OID_PKIX_REGCTRL_REGTOKEN, + SEC_OID_PKIX_REGCTRL_AUTHENTICATOR, + SEC_OID_PKIX_REGCTRL_PKIPUBINFO, + SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS, + SEC_OID_PKIX_REGCTRL_OLD_CERT_ID, + SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY, + SEC_OID_PKIX_REGINFO_UTF8_PAIRS, + SEC_OID_PKIX_REGINFO_CERT_REQUEST, + SEC_OID_EXT_KEY_USAGE_SERVER_AUTH, + SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH, + SEC_OID_EXT_KEY_USAGE_CODE_SIGN, + SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT, + SEC_OID_EXT_KEY_USAGE_TIME_STAMP, + SEC_OID_OCSP_RESPONDER, + + /* Netscape Algorithm OIDs */ + SEC_OID_NETSCAPE_SMIME_KEA, + + /* Skipjack OID -- ### mwelch temporary */ + SEC_OID_FORTEZZA_SKIPJACK, + + /* PKCS 12 V2 oids */ + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC4, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC4, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_2KEY_TRIPLE_DES_CBC, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_128_BIT_RC2_CBC, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC, + SEC_OID_PKCS12_SAFE_CONTENTS_ID, + SEC_OID_PKCS12_PKCS8_SHROUDED_KEY_BAG_ID, + + SEC_OID_PKCS12_V1_KEY_BAG_ID, + SEC_OID_PKCS12_V1_PKCS8_SHROUDED_KEY_BAG_ID, + SEC_OID_PKCS12_V1_CERT_BAG_ID, + SEC_OID_PKCS12_V1_CRL_BAG_ID, + SEC_OID_PKCS12_V1_SECRET_BAG_ID, + SEC_OID_PKCS12_V1_SAFE_CONTENTS_BAG_ID, + SEC_OID_PKCS9_X509_CERT, + SEC_OID_PKCS9_SDSI_CERT, + SEC_OID_PKCS9_X509_CRL, + SEC_OID_PKCS9_FRIENDLY_NAME, + SEC_OID_PKCS9_LOCAL_KEY_ID, + SEC_OID_PKCS12_KEY_USAGE, + + /*Diffe Helman OIDS */ + SEC_OID_X942_DIFFIE_HELMAN_KEY, + + /* Netscape other name types */ + SEC_OID_NETSCAPE_NICKNAME, + + /* Cert Server OIDS */ + SEC_OID_NETSCAPE_RECOVERY_REQUEST, + + /* New PSM certificate management OIDs */ + SEC_OID_CERT_RENEWAL_LOCATOR, + SEC_OID_NS_CERT_EXT_SCOPE_OF_USE, + + SEC_OID_TOTAL +} SECOidTag; + +/* fake OID for DSS sign/verify */ +#define SEC_OID_SHA SEC_OID_MISS_DSS + +typedef enum { + INVALID_CERT_EXTENSION, + UNSUPPORTED_CERT_EXTENSION, + SUPPORTED_CERT_EXTENSION +} SECSupportExtenTag; + +struct SECOidDataStr { + SECItem oid; + SECOidTag offset; + 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..b7f42080d --- /dev/null +++ b/security/nss/lib/util/secplcy.c @@ -0,0 +1,114 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#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..add5d8fac --- /dev/null +++ b/security/nss/lib/util/secplcy.h @@ -0,0 +1,133 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef __secplcy_h__ +#define __secplcy_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..0516a6893 --- /dev/null +++ b/security/nss/lib/util/secport.c @@ -0,0 +1,592 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * 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 "nsslocks.h" + +#ifdef DEBUG +#define THREADMARK +#endif /* DEBUG */ + +#ifdef THREADMARK +#include "prthread.h" +#endif /* THREADMARK */ + +#if defined(XP_UNIX) || defined(XP_MAC) +#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; + +typedef struct threadmark_arena_str { + PLArenaPool arena; + PRUint32 magic; + PRThread *marking_thread; + threadmark_mark *first_mark; +} threadmark_arena; + +#define THREADMARK_MAGIC 0xB8AC9BDD /* In honor of nelsonb */ +#endif /* THREADMARK */ + +/* 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; +} + +#ifdef XP_MAC +char * +PORT_Strdup(const char *cp) +{ + size_t len = PORT_Strlen(cp); + char *buf; + + buf = (char *)PORT_Alloc(len+1); + if (buf == NULL) return; + + PORT_Memcpy(buf,cp,len+1); + return buf; +} +#endif + + +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); + } +} + +void +PORT_SetError(int value) +{ + PR_SetError(value, 0); + return; +} + +int +PORT_GetError(void) +{ + return(PR_GetError()); +} + +/********************* Arena code follows *****************************/ + +PRMonitor * arenaMonitor; + +static void +getArenaLock(void) +{ + if (!arenaMonitor) { + nss_InitMonitor(&arenaMonitor); + } + if (arenaMonitor) + PR_EnterMonitor(arenaMonitor); +} + +static void +releaseArenaLock(void) +{ + if (arenaMonitor) + PR_ExitMonitor(arenaMonitor); +} + +PLArenaPool * +PORT_NewArena(unsigned long chunksize) +{ + PLArenaPool *arena; + + getArenaLock(); +#ifdef THREADMARK + { + threadmark_arena *tarena = (threadmark_arena *) + PORT_ZAlloc(sizeof(threadmark_arena)); + if( (threadmark_arena *)NULL != tarena ) { + arena = &tarena->arena; + tarena->magic = THREADMARK_MAGIC; + } else { + arena = (PLArenaPool *)NULL; + } + } +#else /* THREADMARK */ + arena = (PLArenaPool*)PORT_ZAlloc(sizeof(PLArenaPool)); +#endif /* THREADMARK */ + if ( arena != NULL ) { + PL_InitArenaPool(arena, "security", chunksize, sizeof(double)); + } + releaseArenaLock(); + return(arena); +} + +void * +PORT_ArenaAlloc(PLArenaPool *arena, size_t size) +{ + void *p; + + getArenaLock(); +#ifdef THREADMARK + { + /* Is it one of ours? Assume so and check the magic */ + threadmark_arena *tarena = (threadmark_arena *)arena; + if( THREADMARK_MAGIC == tarena->magic ) { + /* Most likely one of ours. Is there a thread id? */ + if( (PRThread *)NULL != tarena->marking_thread ) { + /* Yes. Has this arena been marked by this thread? */ + if( tarena->marking_thread == PR_GetCurrentThread() ) { + /* Yup. Everything's okay. */ + ; + } else { + /* Nope. BZZT! error */ + releaseArenaLock(); + PORT_SetError(SEC_ERROR_NO_MEMORY); + PORT_Assert(0); + return (void *)NULL; + } + } /* tid != null */ + } /* tarena */ + } /* scope */ +#endif /* THREADMARK */ + + PL_ARENA_ALLOCATE(p, arena, size); + releaseArenaLock(); + if (p == NULL) { + ++port_allocFailures; + PORT_SetError(SEC_ERROR_NO_MEMORY); + } + + return(p); +} + +void * +PORT_ArenaZAlloc(PLArenaPool *arena, size_t size) +{ + void *p; + + getArenaLock(); +#ifdef THREADMARK + { + /* Is it one of ours? Assume so and check the magic */ + threadmark_arena *tarena = (threadmark_arena *)arena; + if( THREADMARK_MAGIC == tarena->magic ) { + /* Most likely one of ours. Is there a thread id? */ + if( (PRThread *)NULL != tarena->marking_thread ) { + /* Yes. Has this arena been marked by this thread? */ + if( tarena->marking_thread == PR_GetCurrentThread() ) { + /* Yup. Everything's okay. */ + ; + } else { + /* No, it was a different thread BZZT! error */ + releaseArenaLock(); + PORT_SetError(SEC_ERROR_NO_MEMORY); + PORT_Assert(0); + return (void *)NULL; + } + } /* tid != null */ + } /* tarena */ + } /* scope */ +#endif /* THREADMARK */ + + PL_ARENA_ALLOCATE(p, arena, size); + releaseArenaLock(); + if (p == NULL) { + ++port_allocFailures; + PORT_SetError(SEC_ERROR_NO_MEMORY); + } else { + PORT_Memset(p, 0, size); + } + + return(p); +} + +/* XXX - need to zeroize!! - jsw */ +void +PORT_FreeArena(PLArenaPool *arena, PRBool zero) +{ + getArenaLock(); + PL_FinishArenaPool(arena); + PORT_Free(arena); + releaseArenaLock(); +} + +void * +PORT_ArenaGrow(PLArenaPool *arena, void *ptr, size_t oldsize, size_t newsize) +{ + PORT_Assert(newsize >= oldsize); + + getArenaLock(); + /* Do we do a THREADMARK check here? */ + PL_ARENA_GROW(ptr, arena, oldsize, ( newsize - oldsize ) ); + releaseArenaLock(); + + return(ptr); +} + +void * +PORT_ArenaMark(PLArenaPool *arena) +{ + void * result; + + getArenaLock(); +#ifdef THREADMARK + { + threadmark_mark *tm, **pw; + + threadmark_arena *tarena = (threadmark_arena *)arena; + if( THREADMARK_MAGIC == tarena->magic ) { + /* one of ours */ + if( (PRThread *)NULL == tarena->marking_thread ) { + /* First mark */ + tarena->marking_thread = PR_GetCurrentThread(); + } else { + if( PR_GetCurrentThread() != tarena->marking_thread ) { + releaseArenaLock(); + PORT_SetError(SEC_ERROR_NO_MEMORY); + PORT_Assert(0); + return (void *)NULL; + } + } + + result = PL_ARENA_MARK(arena); + PL_ARENA_ALLOCATE(tm, arena, sizeof(threadmark_mark)); + if( (threadmark_mark *)NULL == tm ) { + releaseArenaLock(); + PORT_SetError(SEC_ERROR_NO_MEMORY); + return (void *)NULL; + } + + tm->mark = result; + tm->next = (threadmark_mark *)NULL; + + pw = &tarena->first_mark; + while( (threadmark_mark *)NULL != *pw ) { + pw = &(*pw)->next; + } + + *pw = tm; + } else { + /* a "pure" NSPR arena */ + result = PL_ARENA_MARK(arena); + } + } +#else /* THREADMARK */ + result = PL_ARENA_MARK(arena); +#endif /* THREADMARK */ + releaseArenaLock(); + return result; +} + +void +PORT_ArenaRelease(PLArenaPool *arena, void *mark) +{ + getArenaLock(); +#ifdef THREADMARK + { + threadmark_arena *tarena = (threadmark_arena *)arena; + if( THREADMARK_MAGIC == tarena->magic ) { + threadmark_mark **pw, *tm; + + if( PR_GetCurrentThread() != tarena->marking_thread ) { + releaseArenaLock(); + PORT_SetError(SEC_ERROR_NO_MEMORY); + PORT_Assert(0); + return /* no error indication available */ ; + } + + pw = &tarena->first_mark; + while( ((threadmark_mark *)NULL != *pw) && (mark != (*pw)->mark) ) { + pw = &(*pw)->next; + } + + if( (threadmark_mark *)NULL == *pw ) { + /* bad mark */ + releaseArenaLock(); + PORT_SetError(SEC_ERROR_NO_MEMORY); + PORT_Assert(0); + return /* no error indication available */ ; + } + + tm = *pw; + *pw = (threadmark_mark *)NULL; + + PL_ARENA_RELEASE(arena, mark); + + if( (threadmark_mark *)NULL == tarena->first_mark ) { + tarena->marking_thread = (PRThread *)NULL; + } + } else { + PL_ARENA_RELEASE(arena, mark); + } + } +#else /* THREADMARK */ + PL_ARENA_RELEASE(arena, mark); +#endif /* THREADMARK */ + releaseArenaLock(); +} + +void +PORT_ArenaUnmark(PLArenaPool *arena, void *mark) +{ +#ifdef THREADMARK + getArenaLock(); + { + threadmark_arena *tarena = (threadmark_arena *)arena; + if( THREADMARK_MAGIC == tarena->magic ) { + threadmark_mark **pw, *tm; + + if( PR_GetCurrentThread() != tarena->marking_thread ) { + releaseArenaLock(); + PORT_SetError(SEC_ERROR_NO_MEMORY); + PORT_Assert(0); + return /* no error indication available */ ; + } + + pw = &tarena->first_mark; + while( ((threadmark_mark *)NULL != *pw) && (mark != (*pw)->mark) ) { + pw = &(*pw)->next; + } + + if( (threadmark_mark *)NULL == *pw ) { + /* bad mark */ + releaseArenaLock(); + PORT_SetError(SEC_ERROR_NO_MEMORY); + PORT_Assert(0); + return /* no error indication available */ ; + } + + tm = *pw; + *pw = (threadmark_mark *)NULL; + + if( (threadmark_mark *)NULL == tarena->first_mark ) { + tarena->marking_thread = (PRThread *)NULL; + } + } else { + PL_ARENA_RELEASE(arena, mark); + } + } + releaseArenaLock(); +#endif /* THREADMARK */ +} + +char * +PORT_ArenaStrdup(PLArenaPool *arena, char *str) { + int len = PORT_Strlen(str)+1; + char *newstr; + + getArenaLock(); + newstr = (char*)PORT_ArenaAlloc(arena,len); + releaseArenaLock(); + if (newstr) { + PORT_Memcpy(newstr,str,len); + } + return newstr; +} + +/********************** end of arena functions ***********************/ + +/****************** unicode conversion functions ***********************/ +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_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) +{ + SECStatus result = SECSuccess; +#ifdef _WIN32 + PRBool setOK; + + setOK = SetEnvironmentVariable(envVarName, envValue); + if (!setOK) { + SET_ERROR_CODE + result = SECFailure; + } +#elif defined(XP_MAC) + result = SECFailure; +#else + char * encoded; + int putEnvFailed; + + 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); + } +#endif + return result; +} + diff --git a/security/nss/lib/util/secport.h b/security/nss/lib/util/secport.h new file mode 100644 index 000000000..8ccba60ec --- /dev/null +++ b/security/nss/lib/util/secport.h @@ -0,0 +1,274 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +/* + * secport.h - portability interfaces for security libraries + * + * This file abstracts out libc functionality that libsec depends on + * + * NOTE - These are not public interfaces + * + * $Id$ + */ + +#ifndef _SECPORT_H_ +#define _SECPORT_H_ + +/* + * define XP_MAC, XP_WIN, or XP_UNIX, in case they are not defined + * by anyone else + */ +#ifdef macintosh +# ifndef XP_MAC +# define XP_MAC 1 +# endif +#endif + +#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 unix +# ifndef XP_UNIX +# define XP_UNIX +# endif +#endif + +#if defined(__WATCOMC__) || defined(__WATCOM_CPLUSPLUS__) +#include "watcomfx.h" +#endif + +#ifdef XP_MAC +#include <types.h> +#include <time.h> /* for time_t below */ +#else +#include <sys/types.h> +#endif + +#ifdef notdef +#ifdef XP_MAC +#include "NSString.h" +#endif +#endif + +#include <ctype.h> +#include <string.h> +#include <stddef.h> +#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 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_ArenaUnmark(PLArenaPool *arena, void *mark); +extern char *PORT_ArenaStrdup(PLArenaPool *arena, char *str); + +#ifdef __cplusplus +} +#endif + +#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 alphbetically. Thanks! */ + +#ifdef XP_STRING_FUNCS + +#define PORT_Atoi XP_ATOI + +#define PORT_Memcmp XP_MEMCMP +#define PORT_Memcpy XP_MEMCPY +#define PORT_Memmove XP_MEMMOVE +#define PORT_Memset XP_MEMSET + +#define PORT_Strcasecmp XP_STRCASECMP +#define PORT_Strcat XP_STRCAT +#define PORT_Strchr XP_STRCHR +#define PORT_Strrchr XP_STRRCHR +#define PORT_Strcmp XP_STRCMP +#define PORT_Strcpy XP_STRCPY +#define PORT_Strdup XP_STRDUP +#define PORT_Strlen(s) XP_STRLEN(s) +#define PORT_Strncasecmp XP_STRNCASECMP +#define PORT_Strncat strncat +#define PORT_Strncmp XP_STRNCMP +#define PORT_Strncpy strncpy +#define PORT_Strstr XP_STRSTR +#define PORT_Strtok XP_STRTOK_R + +#define PORT_Tolower XP_TO_LOWER + +#else /* XP_STRING_FUNCS */ + +#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 PL_strrchr +#define PORT_Strcmp strcmp +#define PORT_Strcpy strcpy +#ifdef XP_MAC +char *PORT_Strdup(const char *); +#else +#define PORT_Strdup strdup +#endif +#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_Strstr strstr +#define PORT_Strtok strtok + +#define PORT_Tolower tolower + +#endif /* XP_STRING_FUNCS */ + +typedef PRBool (* PORTCharConversionWSwapFunc) (PRBool toUnicode, + unsigned char *inBuf, unsigned int inBufLen, + unsigned char *outBuf, unsigned int maxOutBufLen, + unsigned int *outBufLen, PRBool swapBytes); + +typedef PRBool (* PORTCharConversionFunc) (PRBool toUnicode, + unsigned char *inBuf, unsigned int inBufLen, + unsigned char *outBuf, unsigned int maxOutBufLen, + unsigned int *outBufLen); + +#ifdef __cplusplus +extern "C" { +#endif + +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); + +PR_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 +); + +PR_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 +); + +extern int NSS_PutEnv(const char * envVarName, const char * envValue); + +SEC_END_PROTOS + +#endif /* _SECPORT_H_ */ diff --git a/security/nss/lib/util/secrng.h b/security/nss/lib/util/secrng.h new file mode 100644 index 000000000..c4c8686ef --- /dev/null +++ b/security/nss/lib/util/secrng.h @@ -0,0 +1,82 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef _SECRNG_H_ +#define _SECRNG_H_ +/* + * secrng.h - public data structures and prototypes for the secure random + * number generator + * + * $Id$ + */ + +/******************************************/ +/* +** Random number generation. A cryptographically strong random number +** generator. +*/ + +#include "blapi.h" + +SEC_BEGIN_PROTOS + +/* +** The following 3 functions are provided by the security library +** but are differently implemented for the UNIX, Mac and Win +** versions +*/ + +/* +** Get the "noisiest" information available on the system. +** The amount of data returned depends on the system implementation. +** It will not exceed maxbytes, but may be (much) less. +** Returns number of noise bytes copied into buf, or zero if error. +*/ +extern size_t RNG_GetNoise(void *buf, size_t maxbytes); + +/* +** RNG_SystemInfoForRNG should be called before any use of SSL. It +** gathers up the system specific information to help seed the +** state of the global random number generator. +*/ +extern void RNG_SystemInfoForRNG(void); + +/* +** Use the contents (and stat) of a file to help seed the +** global random number generator. +*/ +extern void RNG_FileForRNG(char *filename); + +SEC_END_PROTOS + +#endif /* _SECUTIL_H_ */ diff --git a/security/nss/lib/util/secrngt.h b/security/nss/lib/util/secrngt.h new file mode 100644 index 000000000..6c1c977c0 --- /dev/null +++ b/security/nss/lib/util/secrngt.h @@ -0,0 +1,44 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifndef _SECRNGT_H_ +#define _SECRNGT_H_ +/* + * secrngt.h - public data structures for the secure random number generator + * + * $Id$ + */ + +/* This file is really dead now. */ + +#endif /* _SECRNGT_H_ */ diff --git a/security/nss/lib/util/sectime.c b/security/nss/lib/util/sectime.c new file mode 100644 index 000000000..d3cca6f87 --- /dev/null +++ b/security/nss/lib/util/sectime.c @@ -0,0 +1,177 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "prlong.h" +#include "prtime.h" +#include "secder.h" +#include "cert.h" +#include "secitem.h" + +const SEC_ASN1Template CERT_ValidityTemplate[] = { + { SEC_ASN1_SEQUENCE, + 0, NULL, sizeof(CERTValidity) }, + { SEC_ASN1_UTC_TIME, + offsetof(CERTValidity,notBefore) }, + { SEC_ASN1_UTC_TIME, + offsetof(CERTValidity,notAfter) }, + { 0 } +}; + +DERTemplate CERTValidityTemplate[] = { + { DER_SEQUENCE, + 0, NULL, sizeof(CERTValidity) }, + { DER_UTC_TIME, + offsetof(CERTValidity,notBefore), }, + { DER_UTC_TIME, + offsetof(CERTValidity,notAfter), }, + { 0, } +}; + +static char *DecodeUTCTime2FormattedAscii (SECItem *utcTimeDER, 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")); +} + +CERTValidity * +CERT_CreateValidity(int64 notBefore, int64 notAfter) +{ + CERTValidity *v; + int rv; + PRArenaPool *arena; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + + if ( !arena ) { + return(0); + } + + v = (CERTValidity*) PORT_ArenaZAlloc(arena, sizeof(CERTValidity)); + if (v) { + v->arena = arena; + rv = DER_TimeToUTCTime(&v->notBefore, notBefore); + if (rv) goto loser; + rv = DER_TimeToUTCTime(&v->notAfter, notAfter); + if (rv) goto loser; + } + return v; + + loser: + CERT_DestroyValidity(v); + return 0; +} + +SECStatus +CERT_CopyValidity(PRArenaPool *arena, CERTValidity *to, CERTValidity *from) +{ + SECStatus rv; + + CERT_DestroyValidity(to); + to->arena = arena; + + rv = SECITEM_CopyItem(arena, &to->notBefore, &from->notBefore); + if (rv) return rv; + rv = SECITEM_CopyItem(arena, &to->notAfter, &from->notAfter); + return rv; +} + +void +CERT_DestroyValidity(CERTValidity *v) +{ + if (v && v->arena) { + PORT_FreeArena(v->arena, PR_FALSE); + } + return; +} + +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(100); + + if ( timeString ) { + PR_FormatTime( timeString, 100, format, &printableTime ); + } + + 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(100); + + if ( timeString ) { + PR_FormatTime( timeString, 100, format, &printableTime ); + } + + 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)); +} diff --git a/security/nss/lib/util/sysrand.c b/security/nss/lib/util/sysrand.c new file mode 100644 index 000000000..f79cb9d53 --- /dev/null +++ b/security/nss/lib/util/sysrand.c @@ -0,0 +1,43 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "seccomon.h" +#ifdef XP_UNIX +#include "unix_rand.c" +#endif +#ifdef XP_WIN +#include "win_rand.c" +#endif +#ifdef XP_MAC +#include "mac_rand.c" +#endif diff --git a/security/nss/lib/util/unix_rand.c b/security/nss/lib/util/unix_rand.c new file mode 100644 index 000000000..6e9c34dbb --- /dev/null +++ b/security/nss/lib/util/unix_rand.c @@ -0,0 +1,792 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include <stdio.h> +#include <string.h> +#include <signal.h> +#include <unistd.h> +#include <errno.h> +#include <stdlib.h> +#include <sys/time.h> +#include <sys/wait.h> +#include <sys/stat.h> +#include <assert.h> +#include "secrng.h" + + +/* + * When copying data to the buffer we want the least signicant bytes + * from the input since those bits are changing the fastest. The address + * of least significant byte depends upon whether we are running on + * a big-endian or little-endian machine. + * + * Does this mean the least signicant bytes are the most significant + * to us? :-) + */ + +static size_t CopyLowBits(void *dst, size_t dstlen, void *src, size_t srclen) +{ + union endianness { + int32 i; + char c[4]; + } u; + + if (srclen <= dstlen) { + memcpy(dst, src, srclen); + return srclen; + } + u.i = 0x01020304; + if (u.c[0] == 0x01) { + /* big-endian case */ + memcpy(dst, (char*)src + (srclen - dstlen), dstlen); + } else { + /* little-endian case */ + memcpy(dst, src, dstlen); + } + return dstlen; +} + +#if defined(SCO) || defined(UNIXWARE) || defined(BSDI) +#include <sys/times.h> + +#define getdtablesize() sysconf(_SC_OPEN_MAX) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + int ticks; + struct tms buffer; + + ticks=times(&buffer); + return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks)); +} + +static void +GiveSystemInfo(void) +{ + long si; + + /* + * Is this really necessary? Why not use rand48 or something? + */ + si = sysconf(_SC_CHILD_MAX); + RNG_RandomUpdate(&si, sizeof(si)); + + si = sysconf(_SC_STREAM_MAX); + RNG_RandomUpdate(&si, sizeof(si)); + + si = sysconf(_SC_OPEN_MAX); + RNG_RandomUpdate(&si, sizeof(si)); +} +#endif + +#if defined(__sun) +#if defined(__svr4) || defined(SVR4) +#include <sys/systeminfo.h> +#include <sys/times.h> +#include <wait.h> + +int gettimeofday(struct timeval *); +int gethostname(char *, int); + +#define getdtablesize() sysconf(_SC_OPEN_MAX) + +static void +GiveSystemInfo(void) +{ + int rv; + char buf[2000]; + + rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } + rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } + rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } +} + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + hrtime_t t; + t = gethrtime(); + if (t) { + return CopyLowBits(buf, maxbytes, &t, sizeof(t)); + } + return 0; +} +#else /* SunOS (Sun, but not SVR4) */ + +#include <sys/wait.h> +extern long sysconf(int name); + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return 0; +} + +static void +GiveSystemInfo(void) +{ + long si; + + /* This is not very good */ + si = sysconf(_SC_CHILD_MAX); + RNG_RandomUpdate(&si, sizeof(si)); +} +#endif +#endif /* Sun */ + +#if defined(__hpux) +#include <sys/unistd.h> +#include <sys/wait.h> + +#define getdtablesize() sysconf(_SC_OPEN_MAX) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + extern int ret_cr16(); + int cr16val; + + cr16val = ret_cr16(); + return CopyLowBits(buf, maxbytes, &cr16val, sizeof(cr16val)); +} + +static void +GiveSystemInfo(void) +{ + long si; + + /* This is not very good */ + si = sysconf(_AES_OS_VERSION); + RNG_RandomUpdate(&si, sizeof(si)); + si = sysconf(_SC_CPU_VERSION); + RNG_RandomUpdate(&si, sizeof(si)); +} +#endif /* HPUX */ + +#if defined(OSF1) +#include <sys/types.h> +#include <sys/sysinfo.h> +#include <sys/wait.h> +#include <sys/systeminfo.h> +#include <c_asm.h> + +static void +GiveSystemInfo(void) +{ + char buf[BUFSIZ]; + int rv; + int off = 0; + + rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } + rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } + rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } +} + +/* + * Use the "get the cycle counter" instruction on the alpha. + * The low 32 bits completely turn over in less than a minute. + * The high 32 bits are some non-counter gunk that changes sometimes. + */ +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + unsigned long t; + + t = asm("rpcc %v0"); + return CopyLowBits(buf, maxbytes, &t, sizeof(t)); +} + +#endif /* Alpha */ + +#if defined(_IBMR2) +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return 0; +} + +static void +GiveSystemInfo(void) +{ + /* XXX haven't found any yet! */ +} +#endif /* IBM R2 */ + +#if defined(__linux) +#include <linux/kernel.h> + +int putenv(const char *); + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return 0; +} + +static void +GiveSystemInfo(void) +{ + /* XXX sysinfo() does not seem be implemented anywhwere */ +#if 0 + struct sysinfo si; + char hn[2000]; + if (sysinfo(&si) == 0) { + RNG_RandomUpdate(&si, sizeof(si)); + } +#endif +} +#endif /* __linux */ + +#if defined(NCR) + +#include <sys/utsname.h> +#include <sys/systeminfo.h> + +#define getdtablesize() sysconf(_SC_OPEN_MAX) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return 0; +} + +static void +GiveSystemInfo(void) +{ + int rv; + char buf[2000]; + + rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } + rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } + rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } +} + +#endif /* NCR */ + + +#if defined(sgi) +#include <fcntl.h> +#undef PRIVATE +#include <sys/mman.h> +#include <sys/syssgi.h> +#include <sys/immu.h> +#include <sys/systeminfo.h> +#include <sys/utsname.h> +#include <wait.h> + +static void +GiveSystemInfo(void) +{ + int rv; + char buf[4096]; + + rv = syssgi(SGI_SYSID, &buf[0]); + if (rv > 0) { + RNG_RandomUpdate(buf, MAXSYSIDSIZE); + } +#ifdef SGI_RDUBLK + rv = syssgi(SGI_RDUBLK, getpid(), &buf[0], sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, sizeof(buf)); + } +#endif /* SGI_RDUBLK */ + rv = syssgi(SGI_INVENT, SGI_INV_READ, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, sizeof(buf)); + } + rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } + rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } + rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } +} + +static size_t GetHighResClock(void *buf, size_t maxbuf) +{ + unsigned phys_addr, raddr, cycleval; + static volatile unsigned *iotimer_addr = NULL; + static int tries = 0; + static int cntr_size; + int mfd; + long s0[2]; + struct timeval tv; + +#ifndef SGI_CYCLECNTR_SIZE +#define SGI_CYCLECNTR_SIZE 165 /* Size user needs to use to read CC */ +#endif + + if (iotimer_addr == NULL) { + if (tries++ > 1) { + /* Don't keep trying if it didn't work */ + return 0; + } + + /* + ** For SGI machines we can use the cycle counter, if it has one, + ** to generate some truly random numbers + */ + phys_addr = syssgi(SGI_QUERY_CYCLECNTR, &cycleval); + if (phys_addr) { + int pgsz = getpagesize(); + int pgoffmask = pgsz - 1; + + raddr = phys_addr & ~pgoffmask; + mfd = open("/dev/mmem", O_RDONLY); + if (mfd < 0) { + return 0; + } + iotimer_addr = (unsigned *) + mmap(0, pgoffmask, PROT_READ, MAP_PRIVATE, mfd, (int)raddr); + if (iotimer_addr == (void*)-1) { + close(mfd); + iotimer_addr = NULL; + return 0; + } + iotimer_addr = (unsigned*) + ((__psint_t)iotimer_addr | (phys_addr & pgoffmask)); + /* + * The file 'mfd' is purposefully not closed. + */ + cntr_size = syssgi(SGI_CYCLECNTR_SIZE); + if (cntr_size < 0) { + struct utsname utsinfo; + + /* + * We must be executing on a 6.0 or earlier system, since the + * SGI_CYCLECNTR_SIZE call is not supported. + * + * The only pre-6.1 platforms with 64-bit counters are + * IP19 and IP21 (Challenge, PowerChallenge, Onyx). + */ + uname(&utsinfo); + if (!strncmp(utsinfo.machine, "IP19", 4) || + !strncmp(utsinfo.machine, "IP21", 4)) + cntr_size = 64; + else + cntr_size = 32; + } + cntr_size /= 8; /* Convert from bits to bytes */ + } + } + + s0[0] = *iotimer_addr; + if (cntr_size > 4) + s0[1] = *(iotimer_addr + 1); + memcpy(buf, (char *)&s0[0], cntr_size); + return CopyLowBits(buf, maxbuf, &s0, cntr_size); +} +#endif + +#if defined(sony) +#include <sys/systeminfo.h> + +#define getdtablesize() sysconf(_SC_OPEN_MAX) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return 0; +} + +static void +GiveSystemInfo(void) +{ + int rv; + char buf[2000]; + + rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } + rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } + rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } +} +#endif /* sony */ + +#if defined(sinix) +#include <unistd.h> +#include <sys/systeminfo.h> +#include <sys/times.h> + +int gettimeofday(struct timeval *, struct timezone *); +int gethostname(char *, int); + +#define getdtablesize() sysconf(_SC_OPEN_MAX) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + int ticks; + struct tms buffer; + + ticks=times(&buffer); + return CopyLowBits(buf, maxbytes, &ticks, sizeof(ticks)); +} + +static void +GiveSystemInfo(void) +{ + int rv; + char buf[2000]; + + rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } + rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } + rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } +} +#endif /* sinix */ + +#if defined(nec_ews) +#include <sys/systeminfo.h> + +#define getdtablesize() sysconf(_SC_OPEN_MAX) + +static size_t +GetHighResClock(void *buf, size_t maxbytes) +{ + return 0; +} + +static void +GiveSystemInfo(void) +{ + int rv; + char buf[2000]; + + rv = sysinfo(SI_MACHINE, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } + rv = sysinfo(SI_RELEASE, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } + rv = sysinfo(SI_HW_SERIAL, buf, sizeof(buf)); + if (rv > 0) { + RNG_RandomUpdate(buf, rv); + } +} +#endif /* nec_ews */ + +size_t RNG_GetNoise(void *buf, size_t maxbytes) +{ + struct timeval tv; + int n = 0; + int c; + + n = GetHighResClock(buf, maxbytes); + maxbytes -= n; + +#if defined(__sun) && (defined(_svr4) || defined(SVR4)) || defined(sony) + (void)gettimeofday(&tv); +#else + (void)gettimeofday(&tv, 0); +#endif + c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_usec, sizeof(tv.tv_usec)); + n += c; + maxbytes -= c; + c = CopyLowBits((char*)buf+n, maxbytes, &tv.tv_sec, sizeof(tv.tv_sec)); + n += c; + return n; +} + +#define SAFE_POPEN_MAXARGS 10 /* must be at least 2 */ + +/* + * safe_popen is static to this module and we know what arguments it is + * called with. Note that this version only supports a single open child + * process at any time. + */ +static pid_t safe_popen_pid; +static struct sigaction oldact; + +static FILE * +safe_popen(char *cmd) +{ + int p[2], fd, argc; + pid_t pid; + char *argv[SAFE_POPEN_MAXARGS + 1]; + FILE *fp; + static char blank[] = " \t"; + static struct sigaction newact; + + if (pipe(p) < 0) + return 0; + + /* Setup signals so that SIGCHLD is ignored as we want to do waitpid */ + newact.sa_handler = SIG_DFL; + newact.sa_flags = 0; + sigfillset(&newact.sa_mask); + sigaction (SIGCHLD, &newact, &oldact); + + pid = fork(); + switch (pid) { + case -1: + close(p[0]); + close(p[1]); + sigaction (SIGCHLD, &oldact, NULL); + return 0; + + case 0: + /* dup write-side of pipe to stderr and stdout */ + if (p[1] != 1) dup2(p[1], 1); + if (p[1] != 2) dup2(p[1], 2); + close(0); + for (fd = getdtablesize(); --fd > 2; close(fd)) + ; + + /* clean up environment in the child process */ + putenv("PATH=/bin:/usr/bin:/sbin:/usr/sbin:/etc:/usr/etc"); + putenv("SHELL=/bin/sh"); + putenv("IFS= \t"); + + /* + * The caller may have passed us a string that is in text + * space. It may be illegal to modify the string + */ + cmd = strdup(cmd); + /* format argv */ + argv[0] = strtok(cmd, blank); + argc = 1; + while ((argv[argc] = strtok(0, blank)) != 0) { + if (++argc == SAFE_POPEN_MAXARGS) { + argv[argc] = 0; + break; + } + } + + /* and away we go */ + execvp(argv[0], argv); + exit(127); + break; + + default: + close(p[1]); + fp = fdopen(p[0], "r"); + if (fp == 0) { + close(p[0]); + sigaction (SIGCHLD, &oldact, NULL); + return 0; + } + break; + } + + /* non-zero means there's a cmd running */ + safe_popen_pid = pid; + return fp; +} + +static int +safe_pclose(FILE *fp) +{ + pid_t pid; + int count, status; + + if ((pid = safe_popen_pid) == 0) + return -1; + safe_popen_pid = 0; + + /* if the child hasn't exited, kill it -- we're done with its output */ + count = 0; + while (waitpid(pid, &status, WNOHANG) == 0) { + if (kill(pid, SIGKILL) < 0 && errno == ESRCH) + break; + if (++count == 1000) + break; + } + + /* Reset SIGCHLD signal hander before returning */ + sigaction(SIGCHLD, &oldact, NULL); + + fclose(fp); + return status; +} + +void RNG_SystemInfoForRNG(void) +{ + FILE *fp; + char buf[BUFSIZ]; + size_t bytes; + extern char **environ; + char **cp; + char *randfile; + char *files[] = { + "/etc/passwd", + "/etc/utmp", + "/tmp", + "/var/tmp", + "/usr/tmp", + 0 + }; + +#ifdef DO_PS +For now it is considered that it is too expensive to run the ps command +for the small amount of entropy it provides. +#if defined(__sun) && (!defined(__svr4) && !defined(SVR4)) || defined(bsdi) || defined(__linux) + static char ps_cmd[] = "ps aux"; +#else + static char ps_cmd[] = "ps -el"; +#endif +#endif /* DO_PS */ + static char netstat_ni_cmd[] = "netstat -ni"; + + GiveSystemInfo(); + + bytes = RNG_GetNoise(buf, sizeof(buf)); + RNG_RandomUpdate(buf, bytes); + +#ifdef DO_PS + fp = safe_popen(ps_cmd); + if (fp != NULL) { + while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0) + RNG_RandomUpdate(buf, bytes); + safe_pclose(fp); + } +#endif + fp = safe_popen(netstat_ni_cmd); + if (fp != NULL) { + while ((bytes = fread(buf, 1, sizeof(buf), fp)) > 0) + RNG_RandomUpdate(buf, bytes); + safe_pclose(fp); + } + + /* + * Pass the C environment and the addresses of the pointers to the + * hash function. This makes the random number function depend on the + * execution environment of the user and on the platform the program + * is running on. + */ + cp = environ; + while (*cp) { + RNG_RandomUpdate(*cp, strlen(*cp)); + cp++; + } + RNG_RandomUpdate(environ, (char*)cp - (char*)environ); + + /* Give in system information */ + if (gethostname(buf, sizeof(buf)) > 0) { + RNG_RandomUpdate(buf, strlen(buf)); + } + GiveSystemInfo(); + + /* If the user points us to a random file, pass it through the rng */ + randfile = getenv("NSRANDFILE"); + if ( ( randfile != NULL ) && ( randfile[0] != '\0') ) { + RNG_FileForRNG(randfile); + } + + /* pass other files through */ + for (cp = files; *cp; cp++) + RNG_FileForRNG(*cp); + +} + +void RNG_FileForRNG(char *fileName) +{ + struct stat stat_buf; + unsigned char buffer[BUFSIZ]; + size_t bytes; + FILE *file; + static size_t totalFileBytes = 0; + + if (stat((char *)fileName, &stat_buf) < 0) + return; + RNG_RandomUpdate(&stat_buf, sizeof(stat_buf)); + + file = fopen((char *)fileName, "r"); + if (file != NULL) { + for (;;) { + bytes = fread(buffer, 1, sizeof(buffer), file); + if (bytes == 0) break; + RNG_RandomUpdate(buffer, bytes); + totalFileBytes += bytes; + if (totalFileBytes > 1024*1024) break; + } + fclose(file); + } + /* + * Pass yet another snapshot of our highest resolution clock into + * the hash function. + */ + bytes = RNG_GetNoise(buffer, sizeof(buffer)); + RNG_RandomUpdate(buffer, bytes); +} diff --git a/security/nss/lib/util/utf8.c b/security/nss/lib/util/utf8.c new file mode 100644 index 000000000..2cce444ef --- /dev/null +++ b/security/nss/lib/util/utf8.c @@ -0,0 +1,2010 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#ifdef DEBUG +static const char CVS_ID[] = "@(#) $RCSfile$ $Revision$ $Date$ $Name$"; +#endif /* DEBUG */ + +#include "seccomon.h" +#include "secport.h" + +/* + * Define this if you want to support UTF-16 in UCS-2 + */ +#define UTF16 + +/* + * 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 + */ + +#if !defined(IS_BIG_ENDIAN) && !defined(IS_LITTLE_ENDIAN) +#error "NSPR should be defining IS_BIG_ENDIAN or IS_LITTLE_ENDIAN" +#endif + +#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 */ + +PR_IMPLEMENT(PRBool) +sec_port_ucs4_utf8_conversion_function +( + PRBool toUnicode, + unsigned char *inBuf, + unsigned int inBufLen, + unsigned char *outBuf, + unsigned int maxOutBufLen, + unsigned int *outBufLen +) +{ +#ifndef TEST_UTF8 + PORT_Assert((unsigned int *)NULL != outBufLen); +#endif /* TEST_UTF8 */ + + 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 if( (inBuf[i] & 0xFC) == 0xF8 ) i += 5; + else if( (inBuf[i] & 0xFE) == 0xFC ) i += 6; + else return PR_FALSE; + + len += 4; + } + + if( len > maxOutBufLen ) { + *outBufLen = len; + return PR_FALSE; + } + + len = 0; + + for( i = 0; i < inBufLen; ) { + if( (inBuf[i] & 0x80) == 0x00 ) { + /* 0000 0000-0000 007F <- 0xxxxxx */ + /* 0abcdefg -> + 00000000 00000000 00000000 0abcdefg */ + + outBuf[len+L_0] = 0x00; + outBuf[len+L_1] = 0x00; + outBuf[len+L_2] = 0x00; + outBuf[len+L_3] = inBuf[i+0] & 0x7F; + + i += 1; + } else if( (inBuf[i] & 0xE0) == 0xC0 ) { + + if( (inBuf[i+1] & 0xC0) != 0x80 ) return PR_FALSE; + + /* 0000 0080-0000 07FF <- 110xxxxx 10xxxxxx */ + /* 110abcde 10fghijk -> + 00000000 00000000 00000abc defghijk */ + + outBuf[len+L_0] = 0x00; + outBuf[len+L_1] = 0x00; + outBuf[len+L_2] = ((inBuf[i+0] & 0x1C) >> 2); + outBuf[len+L_3] = ((inBuf[i+0] & 0x03) << 6) | ((inBuf[i+1] & 0x3F) >> 0); + + i += 2; + } else if( (inBuf[i] & 0xF0) == 0xE0 ) { + + if( (inBuf[i+1] & 0xC0) != 0x80 ) return PR_FALSE; + if( (inBuf[i+2] & 0xC0) != 0x80 ) return PR_FALSE; + + /* 0000 0800-0000 FFFF <- 1110xxxx 10xxxxxx 10xxxxxx */ + /* 1110abcd 10efghij 10klmnop -> + 00000000 00000000 abcdefgh ijklmnop */ + + outBuf[len+L_0] = 0x00; + outBuf[len+L_1] = 0x00; + outBuf[len+L_2] = ((inBuf[i+0] & 0x0F) << 4) | ((inBuf[i+1] & 0x3C) >> 2); + outBuf[len+L_3] = ((inBuf[i+1] & 0x03) << 6) | ((inBuf[i+2] & 0x3F) >> 0); + + i += 3; + } else if( (inBuf[i] & 0xF8) == 0xF0 ) { + + if( (inBuf[i+1] & 0xC0) != 0x80 ) return PR_FALSE; + if( (inBuf[i+2] & 0xC0) != 0x80 ) return PR_FALSE; + if( (inBuf[i+3] & 0xC0) != 0x80 ) return PR_FALSE; + + /* 0001 0000-001F FFFF <- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + /* 11110abc 10defghi 10jklmno 10pqrstu -> + 00000000 000abcde fghijklm nopqrstu */ + + outBuf[len+L_0] = 0x00; + outBuf[len+L_1] = ((inBuf[i+0] & 0x07) << 2) | ((inBuf[i+1] & 0x30) >> 4); + outBuf[len+L_2] = ((inBuf[i+1] & 0x0F) << 4) | ((inBuf[i+2] & 0x3C) >> 2); + outBuf[len+L_3] = ((inBuf[i+2] & 0x03) << 6) | ((inBuf[i+3] & 0x3F) >> 0); + + i += 4; + } else if( (inBuf[i] & 0xFC) == 0xF8 ) { + + if( (inBuf[i+1] & 0xC0) != 0x80 ) return PR_FALSE; + if( (inBuf[i+2] & 0xC0) != 0x80 ) return PR_FALSE; + if( (inBuf[i+3] & 0xC0) != 0x80 ) return PR_FALSE; + if( (inBuf[i+4] & 0xC0) != 0x80 ) return PR_FALSE; + + /* 0020 0000-03FF FFFF <- 111110xx 10xxxxxx ... 10xxxxxx */ + /* 111110ab 10cdefgh 10ijklmn 10opqrst 10uvwxyz -> + 000000ab cdefghij klmnopqr stuvwxyz */ + + outBuf[len+L_0] = inBuf[i+0] & 0x03; + outBuf[len+L_1] = ((inBuf[i+1] & 0x3F) << 2) | ((inBuf[i+2] & 0x30) >> 4); + outBuf[len+L_2] = ((inBuf[i+2] & 0x0F) << 4) | ((inBuf[i+3] & 0x3C) >> 2); + outBuf[len+L_3] = ((inBuf[i+3] & 0x03) << 6) | ((inBuf[i+4] & 0x3F) >> 0); + + i += 5; + } else /* if( (inBuf[i] & 0xFE) == 0xFC ) */ { + + if( (inBuf[i+1] & 0xC0) != 0x80 ) return PR_FALSE; + if( (inBuf[i+2] & 0xC0) != 0x80 ) return PR_FALSE; + if( (inBuf[i+3] & 0xC0) != 0x80 ) return PR_FALSE; + if( (inBuf[i+4] & 0xC0) != 0x80 ) return PR_FALSE; + if( (inBuf[i+5] & 0xC0) != 0x80 ) return PR_FALSE; + + /* 0400 0000-7FFF FFFF <- 1111110x 10xxxxxx ... 10xxxxxx */ + /* 1111110a 10bcdefg 10hijklm 10nopqrs 10tuvwxy 10zABCDE -> + 0abcdefg hijklmno pqrstuvw xyzABCDE */ + + outBuf[len+L_0] = ((inBuf[i+0] & 0x01) << 6) | ((inBuf[i+1] & 0x3F) >> 0); + outBuf[len+L_1] = ((inBuf[i+2] & 0x3F) << 2) | ((inBuf[i+3] & 0x30) >> 4); + outBuf[len+L_2] = ((inBuf[i+3] & 0x0F) << 4) | ((inBuf[i+4] & 0x3C) >> 2); + outBuf[len+L_3] = ((inBuf[i+4] & 0x03) << 6) | ((inBuf[i+5] & 0x3F) >> 0); + + i += 6; + } + + len += 4; + } + + *outBufLen = len; + return PR_TRUE; + } else { + unsigned int i, len = 0; + + for( i = 0; i < inBufLen; i += 4 ) { + if( inBuf[i+L_0] >= 0x04 ) len += 6; + else if( (inBuf[i+L_0] > 0x00) || (inBuf[i+L_1] >= 0x20) ) len += 5; + 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_0] >= 0x04 ) { + /* 0400 0000-7FFF FFFF -> 1111110x 10xxxxxx ... 10xxxxxx */ + /* 0abcdefg hijklmno pqrstuvw xyzABCDE -> + 1111110a 10bcdefg 10hijklm 10nopqrs 10tuvwxy 10zABCDE */ + + outBuf[len+0] = 0xFC | ((inBuf[i+L_0] & 0x40) >> 6); + outBuf[len+1] = 0x80 | ((inBuf[i+L_0] & 0x3F) >> 0); + outBuf[len+2] = 0x80 | ((inBuf[i+L_1] & 0xFC) >> 2); + outBuf[len+3] = 0x80 | ((inBuf[i+L_1] & 0x03) << 4) + | ((inBuf[i+L_2] & 0xF0) >> 4); + outBuf[len+4] = 0x80 | ((inBuf[i+L_2] & 0x0F) << 2) + | ((inBuf[i+L_3] & 0xC0) >> 6); + outBuf[len+5] = 0x80 | ((inBuf[i+L_3] & 0x3F) >> 0); + + len += 6; + } else if( (inBuf[i+L_0] > 0x00) || (inBuf[i+L_1] >= 0x20) ) { + /* 0020 0000-03FF FFFF -> 111110xx 10xxxxxx ... 10xxxxxx */ + /* 000000ab cdefghij klmnopqr stuvwxyz -> + 111110ab 10cdefgh 10ijklmn 10opqrst 10uvwxyz */ + + outBuf[len+0] = 0xF8 | ((inBuf[i+L_0] & 0x03) >> 0); + outBuf[len+1] = 0x80 | ((inBuf[i+L_1] & 0xFC) >> 2); + outBuf[len+2] = 0x80 | ((inBuf[i+L_1] & 0x03) << 4) + | ((inBuf[i+L_2] & 0xF0) >> 4); + outBuf[len+3] = 0x80 | ((inBuf[i+L_2] & 0x0F) << 2) + | ((inBuf[i+L_3] & 0xC0) >> 6); + outBuf[len+4] = 0x80 | ((inBuf[i+L_3] & 0x3F) >> 0); + + len += 5; + } else 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; + } +} + +PR_IMPLEMENT(PRBool) +sec_port_ucs2_utf8_conversion_function +( + PRBool toUnicode, + unsigned char *inBuf, + unsigned int inBufLen, + unsigned char *outBuf, + unsigned int maxOutBufLen, + unsigned int *outBufLen +) +{ +#ifndef TEST_UTF8 + PORT_Assert((unsigned int *)NULL != outBufLen); +#endif /* TEST_UTF8 */ + + 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; +#ifdef UTF16 + } else if( (inBuf[i] & 0xF8) == 0xF0 ) { + i += 4; + len += 4; + + if( (inBuf[i] & 0x04) && + ((inBuf[i] & 0x03) || (inBuf[i+1] & 0x30)) ) { + /* Not representable as UTF16 */ + return PR_FALSE; + } + +#endif /* UTF16 */ + } else return PR_FALSE; + } + + if( len > maxOutBufLen ) { + *outBufLen = len; + return PR_FALSE; + } + + len = 0; + + for( i = 0; i < inBufLen; ) { + if( (inBuf[i] & 0x80) == 0x00 ) { + /* 0000-007F <- 0xxxxxx */ + /* 0abcdefg -> 00000000 0abcdefg */ + + outBuf[len+H_0] = 0x00; + outBuf[len+H_1] = inBuf[i+0] & 0x7F; + + i += 1; + len += 2; + } else if( (inBuf[i] & 0xE0) == 0xC0 ) { + + if( (inBuf[i+1] & 0xC0) != 0x80 ) return PR_FALSE; + + /* 0080-07FF <- 110xxxxx 10xxxxxx */ + /* 110abcde 10fghijk -> 00000abc defghijk */ + + outBuf[len+H_0] = ((inBuf[i+0] & 0x1C) >> 2); + outBuf[len+H_1] = ((inBuf[i+0] & 0x03) << 6) | ((inBuf[i+1] & 0x3F) >> 0); + + i += 2; + len += 2; + } else if( (inBuf[i] & 0xF0) == 0xE0 ) { + + if( (inBuf[i+1] & 0xC0) != 0x80 ) return PR_FALSE; + if( (inBuf[i+2] & 0xC0) != 0x80 ) return PR_FALSE; + + /* 0800-FFFF <- 1110xxxx 10xxxxxx 10xxxxxx */ + /* 1110abcd 10efghij 10klmnop -> abcdefgh ijklmnop */ + + outBuf[len+H_0] = ((inBuf[i+0] & 0x0F) << 4) | ((inBuf[i+1] & 0x3C) >> 2); + outBuf[len+H_1] = ((inBuf[i+1] & 0x03) << 6) | ((inBuf[i+2] & 0x3F) >> 0); + + i += 3; + len += 2; +#ifdef UTF16 + } else if( (inBuf[i] & 0xF8) == 0xF0 ) { + int abcde, BCDE; + + if( (inBuf[i+1] & 0xC0) != 0x80 ) return PR_FALSE; + if( (inBuf[i+2] & 0xC0) != 0x80 ) return PR_FALSE; + if( (inBuf[i+3] & 0xC0) != 0x80 ) return PR_FALSE; + + /* 0001 0000-001F FFFF <- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ + /* 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx -> [D800-DBFF] [DC00-DFFF] */ + + /* 11110abc 10defghi 10jklmno 10pqrstu -> + { Let 0BCDE = abcde - 1 } + 110110BC DEfghijk 110111lm nopqrstu */ + + abcde = ((inBuf[i+0] & 0x07) << 2) | ((inBuf[i+1] & 0x30) >> 4); + BCDE = abcde - 1; + +#ifndef TEST_UTF8 + PORT_Assert(BCDE < 0x10); /* should have been caught above */ +#endif /* TEST_UTF8 */ + + outBuf[len+0+H_0] = 0xD8 | ((BCDE & 0x0C) >> 2); + outBuf[len+0+H_1] = ((BCDE & 0x03) << 6) + | ((inBuf[i+1] & 0x0F) << 2) + | ((inBuf[i+2] & 0x30) >> 4); + outBuf[len+2+H_0] = 0xDC | ((inBuf[i+2] & 0x0C) >> 2); + outBuf[len+2+H_1] = ((inBuf[i+2] & 0x03) << 6) | ((inBuf[i+3] & 0x3F) >> 0); + + i += 4; + len += 4; +#endif /* UTF16 */ + } else return PR_FALSE; + } + + *outBufLen = len; + return PR_TRUE; + } else { + unsigned int i, len = 0; + + 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; +#ifdef UTF16 + 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; + } + } +#endif /* UTF16 */ + 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; +#ifdef UTF16 + } else if( (inBuf[i+H_0] & 0xDC) == 0xD8 ) { + int abcde, BCDE; + +#ifndef TEST_UTF8 + PORT_Assert(((inBuf[i+2+H_0] & 0xDC) == 0xDC) && ((inBufLen - i) > 2)); +#endif /* TEST_UTF8 */ + + /* 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; +#endif /* UTF16 */ + } 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; + } +} + +#ifdef TEST_UTF8 + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +/* + * UCS-4 vectors + */ + +struct ucs4 { + PRUint32 c; + char *utf8; +}; + +/* + * UCS-2 vectors + */ + +struct ucs2 { + PRUint16 c; + char *utf8; +}; + +#ifdef UTF16 +/* + * UTF-16 vectors + */ + +struct utf16 { + PRUint32 c; + PRUint16 w[2]; +}; +#endif /* UTF16 */ + + +/* + * 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" }, + { 0x00110000, "\xF4\x90\x80\x80" }, + { 0x00120000, "\xF4\xA0\x80\x80" }, + { 0x00140000, "\xF5\x80\x80\x80" }, + { 0x00180000, "\xF6\x80\x80\x80" }, + { 0x001FFFFF, "\xF7\xBF\xBF\xBF" }, + + { 0x00200000, "\xF8\x88\x80\x80\x80" }, + { 0x00200001, "\xF8\x88\x80\x80\x81" }, + { 0x00200002, "\xF8\x88\x80\x80\x82" }, + { 0x00200004, "\xF8\x88\x80\x80\x84" }, + { 0x00200008, "\xF8\x88\x80\x80\x88" }, + { 0x00200010, "\xF8\x88\x80\x80\x90" }, + { 0x00200020, "\xF8\x88\x80\x80\xA0" }, + { 0x00200040, "\xF8\x88\x80\x81\x80" }, + { 0x00200080, "\xF8\x88\x80\x82\x80" }, + { 0x00200100, "\xF8\x88\x80\x84\x80" }, + { 0x00200200, "\xF8\x88\x80\x88\x80" }, + { 0x00200400, "\xF8\x88\x80\x90\x80" }, + { 0x00200800, "\xF8\x88\x80\xA0\x80" }, + { 0x00201000, "\xF8\x88\x81\x80\x80" }, + { 0x00202000, "\xF8\x88\x82\x80\x80" }, + { 0x00204000, "\xF8\x88\x84\x80\x80" }, + { 0x00208000, "\xF8\x88\x88\x80\x80" }, + { 0x00210000, "\xF8\x88\x90\x80\x80" }, + { 0x00220000, "\xF8\x88\xA0\x80\x80" }, + { 0x00240000, "\xF8\x89\x80\x80\x80" }, + { 0x00280000, "\xF8\x8A\x80\x80\x80" }, + { 0x00300000, "\xF8\x8C\x80\x80\x80" }, + { 0x003FFFFF, "\xF8\x8F\xBF\xBF\xBF" }, + { 0x00400000, "\xF8\x90\x80\x80\x80" }, + { 0x00400001, "\xF8\x90\x80\x80\x81" }, + { 0x00400002, "\xF8\x90\x80\x80\x82" }, + { 0x00400004, "\xF8\x90\x80\x80\x84" }, + { 0x00400008, "\xF8\x90\x80\x80\x88" }, + { 0x00400010, "\xF8\x90\x80\x80\x90" }, + { 0x00400020, "\xF8\x90\x80\x80\xA0" }, + { 0x00400040, "\xF8\x90\x80\x81\x80" }, + { 0x00400080, "\xF8\x90\x80\x82\x80" }, + { 0x00400100, "\xF8\x90\x80\x84\x80" }, + { 0x00400200, "\xF8\x90\x80\x88\x80" }, + { 0x00400400, "\xF8\x90\x80\x90\x80" }, + { 0x00400800, "\xF8\x90\x80\xA0\x80" }, + { 0x00401000, "\xF8\x90\x81\x80\x80" }, + { 0x00402000, "\xF8\x90\x82\x80\x80" }, + { 0x00404000, "\xF8\x90\x84\x80\x80" }, + { 0x00408000, "\xF8\x90\x88\x80\x80" }, + { 0x00410000, "\xF8\x90\x90\x80\x80" }, + { 0x00420000, "\xF8\x90\xA0\x80\x80" }, + { 0x00440000, "\xF8\x91\x80\x80\x80" }, + { 0x00480000, "\xF8\x92\x80\x80\x80" }, + { 0x00500000, "\xF8\x94\x80\x80\x80" }, + { 0x00600000, "\xF8\x98\x80\x80\x80" }, + { 0x007FFFFF, "\xF8\x9F\xBF\xBF\xBF" }, + { 0x00800000, "\xF8\xA0\x80\x80\x80" }, + { 0x00800001, "\xF8\xA0\x80\x80\x81" }, + { 0x00800002, "\xF8\xA0\x80\x80\x82" }, + { 0x00800004, "\xF8\xA0\x80\x80\x84" }, + { 0x00800008, "\xF8\xA0\x80\x80\x88" }, + { 0x00800010, "\xF8\xA0\x80\x80\x90" }, + { 0x00800020, "\xF8\xA0\x80\x80\xA0" }, + { 0x00800040, "\xF8\xA0\x80\x81\x80" }, + { 0x00800080, "\xF8\xA0\x80\x82\x80" }, + { 0x00800100, "\xF8\xA0\x80\x84\x80" }, + { 0x00800200, "\xF8\xA0\x80\x88\x80" }, + { 0x00800400, "\xF8\xA0\x80\x90\x80" }, + { 0x00800800, "\xF8\xA0\x80\xA0\x80" }, + { 0x00801000, "\xF8\xA0\x81\x80\x80" }, + { 0x00802000, "\xF8\xA0\x82\x80\x80" }, + { 0x00804000, "\xF8\xA0\x84\x80\x80" }, + { 0x00808000, "\xF8\xA0\x88\x80\x80" }, + { 0x00810000, "\xF8\xA0\x90\x80\x80" }, + { 0x00820000, "\xF8\xA0\xA0\x80\x80" }, + { 0x00840000, "\xF8\xA1\x80\x80\x80" }, + { 0x00880000, "\xF8\xA2\x80\x80\x80" }, + { 0x00900000, "\xF8\xA4\x80\x80\x80" }, + { 0x00A00000, "\xF8\xA8\x80\x80\x80" }, + { 0x00C00000, "\xF8\xB0\x80\x80\x80" }, + { 0x00FFFFFF, "\xF8\xBF\xBF\xBF\xBF" }, + { 0x01000000, "\xF9\x80\x80\x80\x80" }, + { 0x01000001, "\xF9\x80\x80\x80\x81" }, + { 0x01000002, "\xF9\x80\x80\x80\x82" }, + { 0x01000004, "\xF9\x80\x80\x80\x84" }, + { 0x01000008, "\xF9\x80\x80\x80\x88" }, + { 0x01000010, "\xF9\x80\x80\x80\x90" }, + { 0x01000020, "\xF9\x80\x80\x80\xA0" }, + { 0x01000040, "\xF9\x80\x80\x81\x80" }, + { 0x01000080, "\xF9\x80\x80\x82\x80" }, + { 0x01000100, "\xF9\x80\x80\x84\x80" }, + { 0x01000200, "\xF9\x80\x80\x88\x80" }, + { 0x01000400, "\xF9\x80\x80\x90\x80" }, + { 0x01000800, "\xF9\x80\x80\xA0\x80" }, + { 0x01001000, "\xF9\x80\x81\x80\x80" }, + { 0x01002000, "\xF9\x80\x82\x80\x80" }, + { 0x01004000, "\xF9\x80\x84\x80\x80" }, + { 0x01008000, "\xF9\x80\x88\x80\x80" }, + { 0x01010000, "\xF9\x80\x90\x80\x80" }, + { 0x01020000, "\xF9\x80\xA0\x80\x80" }, + { 0x01040000, "\xF9\x81\x80\x80\x80" }, + { 0x01080000, "\xF9\x82\x80\x80\x80" }, + { 0x01100000, "\xF9\x84\x80\x80\x80" }, + { 0x01200000, "\xF9\x88\x80\x80\x80" }, + { 0x01400000, "\xF9\x90\x80\x80\x80" }, + { 0x01800000, "\xF9\xA0\x80\x80\x80" }, + { 0x01FFFFFF, "\xF9\xBF\xBF\xBF\xBF" }, + { 0x02000000, "\xFA\x80\x80\x80\x80" }, + { 0x02000001, "\xFA\x80\x80\x80\x81" }, + { 0x02000002, "\xFA\x80\x80\x80\x82" }, + { 0x02000004, "\xFA\x80\x80\x80\x84" }, + { 0x02000008, "\xFA\x80\x80\x80\x88" }, + { 0x02000010, "\xFA\x80\x80\x80\x90" }, + { 0x02000020, "\xFA\x80\x80\x80\xA0" }, + { 0x02000040, "\xFA\x80\x80\x81\x80" }, + { 0x02000080, "\xFA\x80\x80\x82\x80" }, + { 0x02000100, "\xFA\x80\x80\x84\x80" }, + { 0x02000200, "\xFA\x80\x80\x88\x80" }, + { 0x02000400, "\xFA\x80\x80\x90\x80" }, + { 0x02000800, "\xFA\x80\x80\xA0\x80" }, + { 0x02001000, "\xFA\x80\x81\x80\x80" }, + { 0x02002000, "\xFA\x80\x82\x80\x80" }, + { 0x02004000, "\xFA\x80\x84\x80\x80" }, + { 0x02008000, "\xFA\x80\x88\x80\x80" }, + { 0x02010000, "\xFA\x80\x90\x80\x80" }, + { 0x02020000, "\xFA\x80\xA0\x80\x80" }, + { 0x02040000, "\xFA\x81\x80\x80\x80" }, + { 0x02080000, "\xFA\x82\x80\x80\x80" }, + { 0x02100000, "\xFA\x84\x80\x80\x80" }, + { 0x02200000, "\xFA\x88\x80\x80\x80" }, + { 0x02400000, "\xFA\x90\x80\x80\x80" }, + { 0x02800000, "\xFA\xA0\x80\x80\x80" }, + { 0x03000000, "\xFB\x80\x80\x80\x80" }, + { 0x03FFFFFF, "\xFB\xBF\xBF\xBF\xBF" }, + + { 0x04000000, "\xFC\x84\x80\x80\x80\x80" }, + { 0x04000001, "\xFC\x84\x80\x80\x80\x81" }, + { 0x04000002, "\xFC\x84\x80\x80\x80\x82" }, + { 0x04000004, "\xFC\x84\x80\x80\x80\x84" }, + { 0x04000008, "\xFC\x84\x80\x80\x80\x88" }, + { 0x04000010, "\xFC\x84\x80\x80\x80\x90" }, + { 0x04000020, "\xFC\x84\x80\x80\x80\xA0" }, + { 0x04000040, "\xFC\x84\x80\x80\x81\x80" }, + { 0x04000080, "\xFC\x84\x80\x80\x82\x80" }, + { 0x04000100, "\xFC\x84\x80\x80\x84\x80" }, + { 0x04000200, "\xFC\x84\x80\x80\x88\x80" }, + { 0x04000400, "\xFC\x84\x80\x80\x90\x80" }, + { 0x04000800, "\xFC\x84\x80\x80\xA0\x80" }, + { 0x04001000, "\xFC\x84\x80\x81\x80\x80" }, + { 0x04002000, "\xFC\x84\x80\x82\x80\x80" }, + { 0x04004000, "\xFC\x84\x80\x84\x80\x80" }, + { 0x04008000, "\xFC\x84\x80\x88\x80\x80" }, + { 0x04010000, "\xFC\x84\x80\x90\x80\x80" }, + { 0x04020000, "\xFC\x84\x80\xA0\x80\x80" }, + { 0x04040000, "\xFC\x84\x81\x80\x80\x80" }, + { 0x04080000, "\xFC\x84\x82\x80\x80\x80" }, + { 0x04100000, "\xFC\x84\x84\x80\x80\x80" }, + { 0x04200000, "\xFC\x84\x88\x80\x80\x80" }, + { 0x04400000, "\xFC\x84\x90\x80\x80\x80" }, + { 0x04800000, "\xFC\x84\xA0\x80\x80\x80" }, + { 0x05000000, "\xFC\x85\x80\x80\x80\x80" }, + { 0x06000000, "\xFC\x86\x80\x80\x80\x80" }, + { 0x07FFFFFF, "\xFC\x87\xBF\xBF\xBF\xBF" }, + { 0x08000000, "\xFC\x88\x80\x80\x80\x80" }, + { 0x08000001, "\xFC\x88\x80\x80\x80\x81" }, + { 0x08000002, "\xFC\x88\x80\x80\x80\x82" }, + { 0x08000004, "\xFC\x88\x80\x80\x80\x84" }, + { 0x08000008, "\xFC\x88\x80\x80\x80\x88" }, + { 0x08000010, "\xFC\x88\x80\x80\x80\x90" }, + { 0x08000020, "\xFC\x88\x80\x80\x80\xA0" }, + { 0x08000040, "\xFC\x88\x80\x80\x81\x80" }, + { 0x08000080, "\xFC\x88\x80\x80\x82\x80" }, + { 0x08000100, "\xFC\x88\x80\x80\x84\x80" }, + { 0x08000200, "\xFC\x88\x80\x80\x88\x80" }, + { 0x08000400, "\xFC\x88\x80\x80\x90\x80" }, + { 0x08000800, "\xFC\x88\x80\x80\xA0\x80" }, + { 0x08001000, "\xFC\x88\x80\x81\x80\x80" }, + { 0x08002000, "\xFC\x88\x80\x82\x80\x80" }, + { 0x08004000, "\xFC\x88\x80\x84\x80\x80" }, + { 0x08008000, "\xFC\x88\x80\x88\x80\x80" }, + { 0x08010000, "\xFC\x88\x80\x90\x80\x80" }, + { 0x08020000, "\xFC\x88\x80\xA0\x80\x80" }, + { 0x08040000, "\xFC\x88\x81\x80\x80\x80" }, + { 0x08080000, "\xFC\x88\x82\x80\x80\x80" }, + { 0x08100000, "\xFC\x88\x84\x80\x80\x80" }, + { 0x08200000, "\xFC\x88\x88\x80\x80\x80" }, + { 0x08400000, "\xFC\x88\x90\x80\x80\x80" }, + { 0x08800000, "\xFC\x88\xA0\x80\x80\x80" }, + { 0x09000000, "\xFC\x89\x80\x80\x80\x80" }, + { 0x0A000000, "\xFC\x8A\x80\x80\x80\x80" }, + { 0x0C000000, "\xFC\x8C\x80\x80\x80\x80" }, + { 0x0FFFFFFF, "\xFC\x8F\xBF\xBF\xBF\xBF" }, + { 0x10000000, "\xFC\x90\x80\x80\x80\x80" }, + { 0x10000001, "\xFC\x90\x80\x80\x80\x81" }, + { 0x10000002, "\xFC\x90\x80\x80\x80\x82" }, + { 0x10000004, "\xFC\x90\x80\x80\x80\x84" }, + { 0x10000008, "\xFC\x90\x80\x80\x80\x88" }, + { 0x10000010, "\xFC\x90\x80\x80\x80\x90" }, + { 0x10000020, "\xFC\x90\x80\x80\x80\xA0" }, + { 0x10000040, "\xFC\x90\x80\x80\x81\x80" }, + { 0x10000080, "\xFC\x90\x80\x80\x82\x80" }, + { 0x10000100, "\xFC\x90\x80\x80\x84\x80" }, + { 0x10000200, "\xFC\x90\x80\x80\x88\x80" }, + { 0x10000400, "\xFC\x90\x80\x80\x90\x80" }, + { 0x10000800, "\xFC\x90\x80\x80\xA0\x80" }, + { 0x10001000, "\xFC\x90\x80\x81\x80\x80" }, + { 0x10002000, "\xFC\x90\x80\x82\x80\x80" }, + { 0x10004000, "\xFC\x90\x80\x84\x80\x80" }, + { 0x10008000, "\xFC\x90\x80\x88\x80\x80" }, + { 0x10010000, "\xFC\x90\x80\x90\x80\x80" }, + { 0x10020000, "\xFC\x90\x80\xA0\x80\x80" }, + { 0x10040000, "\xFC\x90\x81\x80\x80\x80" }, + { 0x10080000, "\xFC\x90\x82\x80\x80\x80" }, + { 0x10100000, "\xFC\x90\x84\x80\x80\x80" }, + { 0x10200000, "\xFC\x90\x88\x80\x80\x80" }, + { 0x10400000, "\xFC\x90\x90\x80\x80\x80" }, + { 0x10800000, "\xFC\x90\xA0\x80\x80\x80" }, + { 0x11000000, "\xFC\x91\x80\x80\x80\x80" }, + { 0x12000000, "\xFC\x92\x80\x80\x80\x80" }, + { 0x14000000, "\xFC\x94\x80\x80\x80\x80" }, + { 0x18000000, "\xFC\x98\x80\x80\x80\x80" }, + { 0x1FFFFFFF, "\xFC\x9F\xBF\xBF\xBF\xBF" }, + { 0x20000000, "\xFC\xA0\x80\x80\x80\x80" }, + { 0x20000001, "\xFC\xA0\x80\x80\x80\x81" }, + { 0x20000002, "\xFC\xA0\x80\x80\x80\x82" }, + { 0x20000004, "\xFC\xA0\x80\x80\x80\x84" }, + { 0x20000008, "\xFC\xA0\x80\x80\x80\x88" }, + { 0x20000010, "\xFC\xA0\x80\x80\x80\x90" }, + { 0x20000020, "\xFC\xA0\x80\x80\x80\xA0" }, + { 0x20000040, "\xFC\xA0\x80\x80\x81\x80" }, + { 0x20000080, "\xFC\xA0\x80\x80\x82\x80" }, + { 0x20000100, "\xFC\xA0\x80\x80\x84\x80" }, + { 0x20000200, "\xFC\xA0\x80\x80\x88\x80" }, + { 0x20000400, "\xFC\xA0\x80\x80\x90\x80" }, + { 0x20000800, "\xFC\xA0\x80\x80\xA0\x80" }, + { 0x20001000, "\xFC\xA0\x80\x81\x80\x80" }, + { 0x20002000, "\xFC\xA0\x80\x82\x80\x80" }, + { 0x20004000, "\xFC\xA0\x80\x84\x80\x80" }, + { 0x20008000, "\xFC\xA0\x80\x88\x80\x80" }, + { 0x20010000, "\xFC\xA0\x80\x90\x80\x80" }, + { 0x20020000, "\xFC\xA0\x80\xA0\x80\x80" }, + { 0x20040000, "\xFC\xA0\x81\x80\x80\x80" }, + { 0x20080000, "\xFC\xA0\x82\x80\x80\x80" }, + { 0x20100000, "\xFC\xA0\x84\x80\x80\x80" }, + { 0x20200000, "\xFC\xA0\x88\x80\x80\x80" }, + { 0x20400000, "\xFC\xA0\x90\x80\x80\x80" }, + { 0x20800000, "\xFC\xA0\xA0\x80\x80\x80" }, + { 0x21000000, "\xFC\xA1\x80\x80\x80\x80" }, + { 0x22000000, "\xFC\xA2\x80\x80\x80\x80" }, + { 0x24000000, "\xFC\xA4\x80\x80\x80\x80" }, + { 0x28000000, "\xFC\xA8\x80\x80\x80\x80" }, + { 0x30000000, "\xFC\xB0\x80\x80\x80\x80" }, + { 0x3FFFFFFF, "\xFC\xBF\xBF\xBF\xBF\xBF" }, + { 0x40000000, "\xFD\x80\x80\x80\x80\x80" }, + { 0x40000001, "\xFD\x80\x80\x80\x80\x81" }, + { 0x40000002, "\xFD\x80\x80\x80\x80\x82" }, + { 0x40000004, "\xFD\x80\x80\x80\x80\x84" }, + { 0x40000008, "\xFD\x80\x80\x80\x80\x88" }, + { 0x40000010, "\xFD\x80\x80\x80\x80\x90" }, + { 0x40000020, "\xFD\x80\x80\x80\x80\xA0" }, + { 0x40000040, "\xFD\x80\x80\x80\x81\x80" }, + { 0x40000080, "\xFD\x80\x80\x80\x82\x80" }, + { 0x40000100, "\xFD\x80\x80\x80\x84\x80" }, + { 0x40000200, "\xFD\x80\x80\x80\x88\x80" }, + { 0x40000400, "\xFD\x80\x80\x80\x90\x80" }, + { 0x40000800, "\xFD\x80\x80\x80\xA0\x80" }, + { 0x40001000, "\xFD\x80\x80\x81\x80\x80" }, + { 0x40002000, "\xFD\x80\x80\x82\x80\x80" }, + { 0x40004000, "\xFD\x80\x80\x84\x80\x80" }, + { 0x40008000, "\xFD\x80\x80\x88\x80\x80" }, + { 0x40010000, "\xFD\x80\x80\x90\x80\x80" }, + { 0x40020000, "\xFD\x80\x80\xA0\x80\x80" }, + { 0x40040000, "\xFD\x80\x81\x80\x80\x80" }, + { 0x40080000, "\xFD\x80\x82\x80\x80\x80" }, + { 0x40100000, "\xFD\x80\x84\x80\x80\x80" }, + { 0x40200000, "\xFD\x80\x88\x80\x80\x80" }, + { 0x40400000, "\xFD\x80\x90\x80\x80\x80" }, + { 0x40800000, "\xFD\x80\xA0\x80\x80\x80" }, + { 0x41000000, "\xFD\x81\x80\x80\x80\x80" }, + { 0x42000000, "\xFD\x82\x80\x80\x80\x80" }, + { 0x44000000, "\xFD\x84\x80\x80\x80\x80" }, + { 0x48000000, "\xFD\x88\x80\x80\x80\x80" }, + { 0x50000000, "\xFD\x90\x80\x80\x80\x80" }, + { 0x60000000, "\xFD\xA0\x80\x80\x80\x80" }, + { 0x7FFFFFFF, "\xFD\xBF\xBF\xBF\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" } + +}; + +#ifdef UTF16 +/* + * 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 } } + +}; +#endif /* UTF16 */ + +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; +} + +#ifdef UTF16 +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; +} +#endif /* UTF16 */ + +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; + } + +#ifdef UTF16 + /* implement me */ +#endif /* 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; +} + +int +main +( + int argc, + char *argv[] +) +{ + if( test_ucs4_chars() && + test_ucs2_chars() && +#ifdef UTF16 + test_utf16_chars() && +#endif /* UTF16 */ + 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/watcomfx.h b/security/nss/lib/util/watcomfx.h new file mode 100644 index 000000000..bc1d20f72 --- /dev/null +++ b/security/nss/lib/util/watcomfx.h @@ -0,0 +1,59 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#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 */ diff --git a/security/nss/lib/util/win_rand.c b/security/nss/lib/util/win_rand.c new file mode 100644 index 000000000..de2e06ea7 --- /dev/null +++ b/security/nss/lib/util/win_rand.c @@ -0,0 +1,415 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape security libraries. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1994-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License Version 2 or later (the + * "GPL"), in which case the provisions of the GPL are applicable + * instead of those above. If you wish to allow use of your + * version of this file only under the terms of the GPL and not to + * allow others to use your version of this file under the MPL, + * indicate your decision by deleting the provisions above and + * replace them with the notice and other provisions required by + * the GPL. If you do not delete the provisions above, a recipient + * may use your version of this file under either the MPL or the + * GPL. + */ + +#include "secrng.h" +#ifdef XP_WIN +#include <windows.h> +#include <time.h> +#include <io.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <stdio.h> + +#ifndef _WIN32 +#define VTD_Device_ID 5 +#define OP_OVERRIDE _asm _emit 0x66 +#include <dos.h> +#endif + +static BOOL +CurrentClockTickTime(LPDWORD lpdwHigh, LPDWORD lpdwLow) +{ +#ifdef _WIN32 + LARGE_INTEGER liCount; + + if (!QueryPerformanceCounter(&liCount)) + return FALSE; + + *lpdwHigh = liCount.u.HighPart; + *lpdwLow = liCount.u.LowPart; + return TRUE; + +#else /* is WIN16 */ + BOOL bRetVal; + FARPROC lpAPI; + WORD w1, w2, w3, w4; + + // Get direct access to the VTD and query the current clock tick time + _asm { + xor di, di + mov es, di + mov ax, 1684h + mov bx, VTD_Device_ID + int 2fh + mov ax, es + or ax, di + jz EnumerateFailed + + ; VTD API is available. First store the API address (the address actually + ; contains an instruction that causes a fault, the fault handler then + ; makes the ring transition and calls the API in the VxD) + mov word ptr lpAPI, di + mov word ptr lpAPI+2, es + mov ax, 100h ; API function to VTD_Get_Real_Time +; call dword ptr [lpAPI] + call [lpAPI] + + ; Result is in EDX:EAX which we will get 16-bits at a time + mov w2, dx + OP_OVERRIDE + shr dx,10h ; really "shr edx, 16" + mov w1, dx + + mov w4, ax + OP_OVERRIDE + shr ax,10h ; really "shr eax, 16" + mov w3, ax + + mov bRetVal, 1 ; return TRUE + jmp EnumerateExit + + EnumerateFailed: + mov bRetVal, 0 ; return FALSE + + EnumerateExit: + } + + *lpdwHigh = MAKELONG(w2, w1); + *lpdwLow = MAKELONG(w4, w3); + + return bRetVal; +#endif /* is WIN16 */ +} + +size_t RNG_GetNoise(void *buf, size_t maxbuf) +{ + DWORD dwHigh, dwLow, dwVal; + int n = 0; + int nBytes; + time_t sTime; + + if (maxbuf <= 0) + return 0; + + CurrentClockTickTime(&dwHigh, &dwLow); + + // get the maximally changing bits first + nBytes = sizeof(dwLow) > maxbuf ? maxbuf : sizeof(dwLow); + memcpy((char *)buf, &dwLow, nBytes); + n += nBytes; + maxbuf -= nBytes; + + if (maxbuf <= 0) + return n; + + nBytes = sizeof(dwHigh) > maxbuf ? maxbuf : sizeof(dwHigh); + memcpy(((char *)buf) + n, &dwHigh, nBytes); + n += nBytes; + maxbuf -= nBytes; + + if (maxbuf <= 0) + return n; + + // get the number of milliseconds that have elapsed since Windows started + dwVal = GetTickCount(); + + nBytes = sizeof(dwVal) > maxbuf ? maxbuf : sizeof(dwVal); + memcpy(((char *)buf) + n, &dwVal, nBytes); + n += nBytes; + maxbuf -= nBytes; + + if (maxbuf <= 0) + return n; + + // get the time in seconds since midnight Jan 1, 1970 + time(&sTime); + nBytes = sizeof(sTime) > maxbuf ? maxbuf : sizeof(sTime); + memcpy(((char *)buf) + n, &sTime, nBytes); + n += nBytes; + + return n; +} + +static BOOL +EnumSystemFiles(void (*func)(char *)) +{ + int iStatus; + char szSysDir[_MAX_PATH]; + char szFileName[_MAX_PATH]; +#ifdef _WIN32 + struct _finddata_t fdData; + long lFindHandle; +#else + struct _find_t fdData; +#endif + + if (!GetSystemDirectory(szSysDir, sizeof(szSysDir))) + return FALSE; + + // tack *.* on the end so we actually look for files. this will + // not overflow + strcpy(szFileName, szSysDir); + strcat(szFileName, "\\*.*"); + +#ifdef _WIN32 + lFindHandle = _findfirst(szFileName, &fdData); + if (lFindHandle == -1) + return FALSE; +#else + if (_dos_findfirst(szFileName, _A_NORMAL | _A_RDONLY | _A_ARCH | _A_SUBDIR, &fdData) != 0) + return FALSE; +#endif + + do { + // pass the full pathname to the callback + sprintf(szFileName, "%s\\%s", szSysDir, fdData.name); + (*func)(szFileName); + +#ifdef _WIN32 + iStatus = _findnext(lFindHandle, &fdData); +#else + iStatus = _dos_findnext(&fdData); +#endif + } while (iStatus == 0); + +#ifdef _WIN32 + _findclose(lFindHandle); +#endif + + return TRUE; +} + +static DWORD dwNumFiles, dwReadEvery; + +static void +CountFiles(char *file) +{ + dwNumFiles++; +} + +static void +ReadFiles(char *file) +{ + if ((dwNumFiles % dwReadEvery) == 0) + RNG_FileForRNG(file); + + dwNumFiles++; +} + +static void +ReadSystemFiles() +{ + // first count the number of files + dwNumFiles = 0; + if (!EnumSystemFiles(CountFiles)) + return; + + RNG_RandomUpdate(&dwNumFiles, sizeof(dwNumFiles)); + + // now read 10 files + if (dwNumFiles == 0) + return; + + dwReadEvery = dwNumFiles / 10; + if (dwReadEvery == 0) + dwReadEvery = 1; // less than 10 files + + dwNumFiles = 0; + EnumSystemFiles(ReadFiles); +} + +void RNG_SystemInfoForRNG(void) +{ + DWORD dwVal; + char buffer[256]; + int nBytes; +#ifdef _WIN32 + MEMORYSTATUS sMem; + DWORD dwSerialNum; + DWORD dwComponentLen; + DWORD dwSysFlags; + char volName[128]; + DWORD dwSectors, dwBytes, dwFreeClusters, dwNumClusters; + HANDLE hVal; +#else + int iVal; + HTASK hTask; + WORD wDS, wCS; + LPSTR lpszEnv; +#endif + + nBytes = RNG_GetNoise(buffer, 20); // get up to 20 bytes + RNG_RandomUpdate(buffer, nBytes); + +#ifdef _WIN32 + sMem.dwLength = sizeof(sMem); + GlobalMemoryStatus(&sMem); // assorted memory stats + RNG_RandomUpdate(&sMem, sizeof(sMem)); + + dwVal = GetLogicalDrives(); + RNG_RandomUpdate(&dwVal, sizeof(dwVal)); // bitfields in bits 0-25 + +#else + dwVal = GetFreeSpace(0); + RNG_RandomUpdate(&dwVal, sizeof(dwVal)); + + _asm mov wDS, ds; + _asm mov wCS, cs; + RNG_RandomUpdate(&wDS, sizeof(wDS)); + RNG_RandomUpdate(&wCS, sizeof(wCS)); +#endif + +#ifdef _WIN32 + dwVal = sizeof(buffer); + if (GetComputerName(buffer, &dwVal)) + RNG_RandomUpdate(buffer, dwVal); + +/* XXX This is code that got yanked because of NSPR20. We should put it + * back someday. + */ +#ifdef notdef + { + POINT ptVal; + GetCursorPos(&ptVal); + RNG_RandomUpdate(&ptVal, sizeof(ptVal)); + } + + dwVal = GetQueueStatus(QS_ALLINPUT); // high and low significant + RNG_RandomUpdate(&dwVal, sizeof(dwVal)); + + { + HWND hWnd; + hWnd = GetClipboardOwner(); // 2 or 4 bytes + RNG_RandomUpdate((void *)&hWnd, sizeof(hWnd)); + } + + { + UUID sUuid; + UuidCreate(&sUuid); // this will fail on machines with no ethernet + RNG_RandomUpdate(&sUuid, sizeof(sUuid)); // boards. shove the bits in regardless + } +#endif + + hVal = GetCurrentProcess(); // 4 byte handle of current task + RNG_RandomUpdate(&hVal, sizeof(hVal)); + + dwVal = GetCurrentProcessId(); // process ID (4 bytes) + RNG_RandomUpdate(&dwVal, sizeof(dwVal)); + + volName[0] = '\0'; + buffer[0] = '\0'; + GetVolumeInformation(NULL, + volName, + sizeof(volName), + &dwSerialNum, + &dwComponentLen, + &dwSysFlags, + buffer, + sizeof(buffer)); + + RNG_RandomUpdate(volName, strlen(volName)); + RNG_RandomUpdate(&dwSerialNum, sizeof(dwSerialNum)); + RNG_RandomUpdate(&dwComponentLen, sizeof(dwComponentLen)); + RNG_RandomUpdate(&dwSysFlags, sizeof(dwSysFlags)); + RNG_RandomUpdate(buffer, strlen(buffer)); + + if (GetDiskFreeSpace(NULL, &dwSectors, &dwBytes, &dwFreeClusters, &dwNumClusters)) { + RNG_RandomUpdate(&dwSectors, sizeof(dwSectors)); + RNG_RandomUpdate(&dwBytes, sizeof(dwBytes)); + RNG_RandomUpdate(&dwFreeClusters, sizeof(dwFreeClusters)); + RNG_RandomUpdate(&dwNumClusters, sizeof(dwNumClusters)); + } + +#else /* is WIN16 */ + hTask = GetCurrentTask(); + RNG_RandomUpdate((void *)&hTask, sizeof(hTask)); + + iVal = GetNumTasks(); + RNG_RandomUpdate(&iVal, sizeof(iVal)); // number of running tasks + + lpszEnv = GetDOSEnvironment(); + while (*lpszEnv != '\0') { + RNG_RandomUpdate(lpszEnv, strlen(lpszEnv)); + + lpszEnv += strlen(lpszEnv) + 1; + } +#endif /* is WIN16 */ + + // now let's do some files + ReadSystemFiles(); + + nBytes = RNG_GetNoise(buffer, 20); // get up to 20 bytes + RNG_RandomUpdate(buffer, nBytes); +} + +void RNG_FileForRNG(char *filename) +{ + FILE* file; + int nBytes; + struct stat stat_buf; + unsigned char buffer[1024]; + + static DWORD totalFileBytes = 0; + + /* windows doesn't initialize all the bytes in the stat buf, + * so initialize them all here to avoid UMRs. + */ + memset(&stat_buf, 0, sizeof stat_buf); + + if (stat((char *)filename, &stat_buf) < 0) + return; + + RNG_RandomUpdate((unsigned char*)&stat_buf, sizeof(stat_buf)); + + file = fopen((char *)filename, "r"); + if (file != NULL) { + for (;;) { + size_t bytes = fread(buffer, 1, sizeof(buffer), file); + + if (bytes == 0) + break; + + RNG_RandomUpdate(buffer, bytes); + totalFileBytes += bytes; + if (totalFileBytes > 250000) + break; + } + + fclose(file); + } + + nBytes = RNG_GetNoise(buffer, 20); // get up to 20 bytes + RNG_RandomUpdate(buffer, nBytes); +} + +#endif /* is XP_WIN */ |