diff options
author | cvs2hg <devnull@localhost> | 2013-02-21 22:12:45 +0100 |
---|---|---|
committer | cvs2hg <devnull@localhost> | 2013-02-21 22:12:45 +0100 |
commit | ba0cbe2c7d3c2b7640fb84c36f02aab0459c4e0b (patch) | |
tree | 916501d96e0b3a1edc1aa75f66ecf79c6abf814c /security/nss/cmd | |
parent | 52117abf63f8c4dbeb439c0dec376989845de7c6 (diff) | |
parent | db9894ead5167463ea02f460e3b4e66221d6d60e (diff) | |
download | nss-hg-ba0cbe2c7d3c2b7640fb84c36f02aab0459c4e0b.tar.gz |
artificial changeset: close fixup head 3836ae9d564a for tag Makefile
Diffstat (limited to 'security/nss/cmd')
393 files changed, 81144 insertions, 0 deletions
diff --git a/security/nss/cmd/.cvsignore b/security/nss/cmd/.cvsignore new file mode 100644 index 000000000..6329db22e --- /dev/null +++ b/security/nss/cmd/.cvsignore @@ -0,0 +1 @@ +.gdbinit diff --git a/security/nss/cmd/Makefile b/security/nss/cmd/Makefile new file mode 100644 index 000000000..5e716b9b3 --- /dev/null +++ b/security/nss/cmd/Makefile @@ -0,0 +1,182 @@ +#! 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. +# + +CORE_DEPTH = ../.. +DEPTH = ../.. + +include manifest.mn +include $(CORE_DEPTH)/coreconf/config.mk + +# These sources were once in this directory, but now are gone. +MISSING_SOURCES = \ + addcert.c \ + berparse.c \ + cert.c \ + key.c \ + key_rand.c \ + keygen.c \ + sec_fe.c \ + sec_read.c \ + secarb.c \ + secutil.c \ + $(NULL) + +# we don't build these any more, but the sources are still here +OBSOLETE = \ + berdec.c \ + berdump.c \ + cypher.c \ + dumpcert.c \ + listcerts.c \ + mkdongle.c \ + p12exprt.c \ + p12imprt.c \ + rc4.c \ + sign.c \ + unwrap.c \ + vector.c \ + verify.c \ + wrap.c \ + $(NULL) + +# the base files for the executables +# hey -- keep these alphabetical, please +EXEC_SRCS = \ + $(NULL) + +# files that generate two separate objects and executables +# BI_SRCS = \ +# keyutil.c \ +# p7env.c \ +# tstclnt.c \ +# $(NULL) + +# -I$(CORE_DEPTH)/security/lib/cert \ +# -I$(CORE_DEPTH)/security/lib/key \ +# -I$(CORE_DEPTH)/security/lib/util \ + +INCLUDES += \ + -I$(DIST)/../public/security \ + -I./include \ + $(NULL) + +TBD_DIRS = rsh rshd rdist ssld + +# For the time being, sec stuff is export only +# US_FLAGS = -DEXPORT_VERSION -DUS_VERSION + +US_FLAGS = -DEXPORT_VERSION +EXPORT_FLAGS = -DEXPORT_VERSION + +BASE_LIBS = \ + $(DIST)/lib/libdbm.$(LIB_SUFFIX) \ + $(DIST)/lib/libxp.$(LIB_SUFFIX) \ + $(DIST)/lib/libnspr.$(LIB_SUFFIX) \ + $(NULL) + +# $(DIST)/lib/libpurenspr.$(LIB_SUFFIX) \ + +#There is a circular dependancy in security/lib, and here is a gross fix +SEC_LIBS = \ + $(DIST)/lib/libsecnav.$(LIB_SUFFIX) \ + $(DIST)/lib/libssl.$(LIB_SUFFIX) \ + $(DIST)/lib/libpkcs7.$(LIB_SUFFIX) \ + $(DIST)/lib/libcert.$(LIB_SUFFIX) \ + $(DIST)/lib/libkey.$(LIB_SUFFIX) \ + $(DIST)/lib/libsecmod.$(LIB_SUFFIX) \ + $(DIST)/lib/libcrypto.$(LIB_SUFFIX) \ + $(DIST)/lib/libsecutil.$(LIB_SUFFIX) \ + $(DIST)/lib/libssl.$(LIB_SUFFIX) \ + $(DIST)/lib/libpkcs7.$(LIB_SUFFIX) \ + $(DIST)/lib/libcert.$(LIB_SUFFIX) \ + $(DIST)/lib/libkey.$(LIB_SUFFIX) \ + $(DIST)/lib/libsecmod.$(LIB_SUFFIX) \ + $(DIST)/lib/libcrypto.$(LIB_SUFFIX) \ + $(DIST)/lib/libsecutil.$(LIB_SUFFIX) \ + $(DIST)/lib/libhash.$(LIB_SUFFIX) \ + $(NULL) + +MYLIB = lib/$(OBJDIR)/libsectool.$(LIB_SUFFIX) + +US_LIBS = $(MYLIB) $(SEC_LIBS) $(BASE_LIBS) $(MYLIB) $(BASE_LIBS) +EX_LIBS = $(MYLIB) $(SEC_LIBS) $(BASE_LIBS) $(MYLIB) $(BASE_LIBS) + +REQUIRES = libxp nspr security + +CSRCS = $(EXEC_SRCS) $(BI_SRCS) + +OBJS = $(CSRCS:.c=.o) $(BI_SRCS:.c=-us.o) $(BI_SRCS:.c=-ex.o) + +PROGS = $(addprefix $(OBJDIR)/, $(EXEC_SRCS:.c=$(BIN_SUFFIX))) +US_PROGS = $(addprefix $(OBJDIR)/, $(BI_SRCS:.c=-us$(BIN_SUFFIX))) +EX_PROGS = $(addprefix $(OBJDIR)/, $(BI_SRCS:.c=-ex$(BIN_SUFFIX))) + + +NON_DIRS = $(PROGS) $(US_PROGS) $(EX_PROGS) +TARGETS = $(NON_DIRS) + +include $(CORE_DEPTH)/coreconf/rules.mk + + +ifneq ($(OS_TARGET),OS2) +$(OBJDIR)/%-us.o: %.c + @$(MAKE_OBJDIR) + $(CCF) -o $@ $(US_FLAGS) -c $*.c + +$(OBJDIR)/%-ex.o: %.c + @$(MAKE_OBJDIR) + $(CCF) -o $@ $(EXPORT_FLAGS) -c $*.c + +$(OBJDIR)/%.o: %.c + @$(MAKE_OBJDIR) + $(CCF) -o $@ $(EXPORT_FLAGS) -c $*.c + +$(US_PROGS):$(OBJDIR)/%-us: $(OBJDIR)/%-us.o $(US_LIBS) + @$(MAKE_OBJDIR) + $(CCF) -o $@ $(OBJDIR)/$*-us.o $(LDFLAGS) $(US_LIBS) $(OS_LIBS) + +$(EX_PROGS):$(OBJDIR)/%-ex: $(OBJDIR)/%-ex.o $(EX_LIBS) + @$(MAKE_OBJDIR) + $(CCF) -o $@ $(OBJDIR)/$*-ex.o $(LDFLAGS) $(EX_LIBS) $(OS_LIBS) + +$(PROGS):$(OBJDIR)/%: $(OBJDIR)/%.o $(EX_LIBS) + @$(MAKE_OBJDIR) + $(CCF) -o $@ $@.o $(LDFLAGS) $(EX_LIBS) $(OS_LIBS) + +#install:: $(TARGETS) +# $(INSTALL) $(TARGETS) $(DIST)/bin +endif + +symbols:: + @echo "TARGETS = $(TARGETS)" diff --git a/security/nss/cmd/SSLsample/Makefile b/security/nss/cmd/SSLsample/Makefile new file mode 100644 index 000000000..cf741f387 --- /dev/null +++ b/security/nss/cmd/SSLsample/Makefile @@ -0,0 +1,44 @@ +#! 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. +# + +# do these once for each target program +all default export libs program install release_export:: + $(MAKE) -f make.client $@ + $(MAKE) -f make.server $@ + +# only do these things once for the whole directory +depend dependclean clean clobber realclean clobber_all release_classes release_clean release_cpdistdir release_export release_jars release_md release_policy show:: + $(MAKE) -f make.client $@ + + diff --git a/security/nss/cmd/SSLsample/Makefile.NSS b/security/nss/cmd/SSLsample/Makefile.NSS new file mode 100644 index 000000000..0a3545f4f --- /dev/null +++ b/security/nss/cmd/SSLsample/Makefile.NSS @@ -0,0 +1,58 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +ARCH := $(shell uname) + +ifeq ($(ARCH), SunOS) + DEFINES = -KPIC -DSVR4 -DSOLARIS -DSYSV -D__svr4 -D__svr4__ \ + -D_REENTRANT -DSOLARIS2_5 -D_SVID_GETTOD -DXP_UNIX -UDEBUG -DNDEBUG \ + -DXP_UNIX + INCPATH = -I. -I../include/dbm -I../include/nspr -I../include/security + LIBPATH = -L../lib + LIBS = -lnss -lssl -lpkcs7 -lpkcs12 -lsecmod -lcert -lkey \ + -lcrypto -lsecutil -lhash -ldbm -lplc4 -lplds4 -lnspr4 -lsocket -lnsl + CFLAGS = -g + CC = cc +endif # SunOS + +# The rules to build the sample apps appear below. + +server: + $(CC) $(CFLAGS) $@.c -o $@ $(DEFINES) $(INCPATH) $(LIBPATH) $(LIBS) + +client: + $(CC) $(CFLAGS) $@.c -o $@ $(DEFINES) $(INCPATH) $(LIBPATH) $(LIBS) + +clean: + rm -fr server client server.o client.o + diff --git a/security/nss/cmd/SSLsample/NSPRerrs.h b/security/nss/cmd/SSLsample/NSPRerrs.h new file mode 100644 index 000000000..bacdef6b2 --- /dev/null +++ b/security/nss/cmd/SSLsample/NSPRerrs.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. + */ +/* General NSPR 2.0 errors */ +/* Caller must #include "prerror.h" */ + +ER2( PR_OUT_OF_MEMORY_ERROR, "Memory allocation attempt failed." ) +ER2( PR_BAD_DESCRIPTOR_ERROR, "Invalid file descriptor." ) +ER2( PR_WOULD_BLOCK_ERROR, "The operation would have blocked." ) +ER2( PR_ACCESS_FAULT_ERROR, "Invalid memory address argument." ) +ER2( PR_INVALID_METHOD_ERROR, "Invalid function for file type." ) +ER2( PR_ILLEGAL_ACCESS_ERROR, "Invalid memory address argument." ) +ER2( PR_UNKNOWN_ERROR, "Some unknown error has occurred." ) +ER2( PR_PENDING_INTERRUPT_ERROR,"Operation interrupted by another thread." ) +ER2( PR_NOT_IMPLEMENTED_ERROR, "function not implemented." ) +ER2( PR_IO_ERROR, "I/O function error." ) +ER2( PR_IO_TIMEOUT_ERROR, "I/O operation timed out." ) +ER2( PR_IO_PENDING_ERROR, "I/O operation on busy file descriptor." ) +ER2( PR_DIRECTORY_OPEN_ERROR, "The directory could not be opened." ) +ER2( PR_INVALID_ARGUMENT_ERROR, "Invalid function argument." ) +ER2( PR_ADDRESS_NOT_AVAILABLE_ERROR, "Network address not available (in use?)." ) +ER2( PR_ADDRESS_NOT_SUPPORTED_ERROR, "Network address type not supported." ) +ER2( PR_IS_CONNECTED_ERROR, "Already connected." ) +ER2( PR_BAD_ADDRESS_ERROR, "Network address is invalid." ) +ER2( PR_ADDRESS_IN_USE_ERROR, "Local Network address is in use." ) +ER2( PR_CONNECT_REFUSED_ERROR, "Connection refused by peer." ) +ER2( PR_NETWORK_UNREACHABLE_ERROR, "Network address is presently unreachable." ) +ER2( PR_CONNECT_TIMEOUT_ERROR, "Connection attempt timed out." ) +ER2( PR_NOT_CONNECTED_ERROR, "Network file descriptor is not connected." ) +ER2( PR_LOAD_LIBRARY_ERROR, "Failure to load dynamic library." ) +ER2( PR_UNLOAD_LIBRARY_ERROR, "Failure to unload dynamic library." ) +ER2( PR_FIND_SYMBOL_ERROR, +"Symbol not found in any of the loaded dynamic libraries." ) +ER2( PR_INSUFFICIENT_RESOURCES_ERROR, "Insufficient system resources." ) +ER2( PR_DIRECTORY_LOOKUP_ERROR, +"A directory lookup on a network address has failed." ) +ER2( PR_TPD_RANGE_ERROR, +"Attempt to access a TPD key that is out of range." ) +ER2( PR_PROC_DESC_TABLE_FULL_ERROR, "Process open FD table is full." ) +ER2( PR_SYS_DESC_TABLE_FULL_ERROR, "System open FD table is full." ) +ER2( PR_NOT_SOCKET_ERROR, +"Network operation attempted on non-network file descriptor." ) +ER2( PR_NOT_TCP_SOCKET_ERROR, +"TCP-specific function attempted on a non-TCP file descriptor." ) +ER2( PR_SOCKET_ADDRESS_IS_BOUND_ERROR, "TCP file descriptor is already bound." ) +ER2( PR_NO_ACCESS_RIGHTS_ERROR, "Access Denied." ) +ER2( PR_OPERATION_NOT_SUPPORTED_ERROR, +"The requested operation is not supported by the platform." ) +ER2( PR_PROTOCOL_NOT_SUPPORTED_ERROR, +"The host operating system does not support the protocol requested." ) +ER2( PR_REMOTE_FILE_ERROR, "Access to the remote file has been severed." ) +ER2( PR_BUFFER_OVERFLOW_ERROR, +"The value requested is too large to be stored in the data buffer provided." ) +ER2( PR_CONNECT_RESET_ERROR, "TCP connection reset by peer." ) +ER2( PR_RANGE_ERROR, "Unused." ) +ER2( PR_DEADLOCK_ERROR, "The operation would have deadlocked." ) +ER2( PR_FILE_IS_LOCKED_ERROR, "The file is already locked." ) +ER2( PR_FILE_TOO_BIG_ERROR, +"Write would result in file larger than the system allows." ) +ER2( PR_NO_DEVICE_SPACE_ERROR, "The device for storing the file is full." ) +ER2( PR_PIPE_ERROR, "Unused." ) +ER2( PR_NO_SEEK_DEVICE_ERROR, "Unused." ) +ER2( PR_IS_DIRECTORY_ERROR, +"Cannot perform a normal file operation on a directory." ) +ER2( PR_LOOP_ERROR, "Symbolic link loop." ) +ER2( PR_NAME_TOO_LONG_ERROR, "File name is too long." ) +ER2( PR_FILE_NOT_FOUND_ERROR, "File not found." ) +ER2( PR_NOT_DIRECTORY_ERROR, +"Cannot perform directory operation on a normal file." ) +ER2( PR_READ_ONLY_FILESYSTEM_ERROR, +"Cannot write to a read-only file system." ) +ER2( PR_DIRECTORY_NOT_EMPTY_ERROR, +"Cannot delete a directory that is not empty." ) +ER2( PR_FILESYSTEM_MOUNTED_ERROR, +"Cannot delete or rename a file object while the file system is busy." ) +ER2( PR_NOT_SAME_DEVICE_ERROR, +"Cannot rename a file to a file system on another device." ) +ER2( PR_DIRECTORY_CORRUPTED_ERROR, +"The directory object in the file system is corrupted." ) +ER2( PR_FILE_EXISTS_ERROR, +"Cannot create or rename a filename that already exists." ) +ER2( PR_MAX_DIRECTORY_ENTRIES_ERROR, +"Directory is full. No additional filenames may be added." ) +ER2( PR_INVALID_DEVICE_STATE_ERROR, +"The required device was in an invalid state." ) +ER2( PR_DEVICE_IS_LOCKED_ERROR, "The device is locked." ) +ER2( PR_NO_MORE_FILES_ERROR, "No more entries in the directory." ) +ER2( PR_END_OF_FILE_ERROR, "Encountered end of file." ) +ER2( PR_FILE_SEEK_ERROR, "Seek error." ) +ER2( PR_FILE_IS_BUSY_ERROR, "The file is busy." ) +ER2( PR_IN_PROGRESS_ERROR, +"Operation is still in progress (probably a non-blocking connect)." ) +ER2( PR_ALREADY_INITIATED_ERROR, +"Operation has already been initiated (probably a non-blocking connect)." ) + +#ifdef PR_GROUP_EMPTY_ERROR +ER2( PR_GROUP_EMPTY_ERROR, "The wait group is empty." ) +#endif + +#ifdef PR_INVALID_STATE_ERROR +ER2( PR_INVALID_STATE_ERROR, "Object state improper for request." ) +#endif + +ER2( PR_MAX_ERROR, "Placeholder for the end of the list" ) diff --git a/security/nss/cmd/SSLsample/README b/security/nss/cmd/SSLsample/README new file mode 100644 index 000000000..2c4c09110 --- /dev/null +++ b/security/nss/cmd/SSLsample/README @@ -0,0 +1,43 @@ +These sample programs can be built in either of two ways: +1) is the NSS source tree, using the coreconf build system, and +2) stand alone (as part of the NSS distribution). + +The following makefiles are used only when building in the NSS source tree +using coreconf. These are NOT part of the distribution. + +Makefile +client.mn +server.mn +config.mk +make.client +make.server + +The following makefiles are used only when building in the NSS distribution. +These files are part of the distribution. + +Makefile.NSS +nmakefile95.nss +nmakefilent.nss + + +The following source files are common to both build environments and are +part of the distribution. + +NSPRerrs.h +SECerrs.h +SSLerrs.h +client.c +getopt.c +server.c +sslerror.h + +In the NSS 2.0 distribution, the sample code and makefiles are in a +directory named "samples". The directories relevant to building +in the distributed tree are: + +./samples +./include/dbm +./include/nspr +./include/security +./lib + diff --git a/security/nss/cmd/SSLsample/SECerrs.h b/security/nss/cmd/SSLsample/SECerrs.h new file mode 100644 index 000000000..2059df6a2 --- /dev/null +++ b/security/nss/cmd/SSLsample/SECerrs.h @@ -0,0 +1,441 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* General security error codes */ +/* Caller must #include "secerr.h" */ + +ER3(SEC_ERROR_IO, SEC_ERROR_BASE + 0, +"An I/O error occurred during security authorization.") + +ER3(SEC_ERROR_LIBRARY_FAILURE, SEC_ERROR_BASE + 1, +"security library failure.") + +ER3(SEC_ERROR_BAD_DATA, SEC_ERROR_BASE + 2, +"security library: received bad data.") + +ER3(SEC_ERROR_OUTPUT_LEN, SEC_ERROR_BASE + 3, +"security library: output length error.") + +ER3(SEC_ERROR_INPUT_LEN, SEC_ERROR_BASE + 4, +"security library has experienced an input length error.") + +ER3(SEC_ERROR_INVALID_ARGS, SEC_ERROR_BASE + 5, +"security library: invalid arguments.") + +ER3(SEC_ERROR_INVALID_ALGORITHM, SEC_ERROR_BASE + 6, +"security library: invalid algorithm.") + +ER3(SEC_ERROR_INVALID_AVA, SEC_ERROR_BASE + 7, +"security library: invalid AVA.") + +ER3(SEC_ERROR_INVALID_TIME, SEC_ERROR_BASE + 8, +"Improperly formatted time string.") + +ER3(SEC_ERROR_BAD_DER, SEC_ERROR_BASE + 9, +"security library: improperly formatted DER-encoded message.") + +ER3(SEC_ERROR_BAD_SIGNATURE, SEC_ERROR_BASE + 10, +"Peer's certificate has an invalid signature.") + +ER3(SEC_ERROR_EXPIRED_CERTIFICATE, SEC_ERROR_BASE + 11, +"Peer's Certificate has expired.") + +ER3(SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_BASE + 12, +"Peer's Certificate has been revoked.") + +ER3(SEC_ERROR_UNKNOWN_ISSUER, SEC_ERROR_BASE + 13, +"Peer's Certificate issuer is not recognized.") + +ER3(SEC_ERROR_BAD_KEY, SEC_ERROR_BASE + 14, +"Peer's public key is invalid.") + +ER3(SEC_ERROR_BAD_PASSWORD, SEC_ERROR_BASE + 15, +"The security password entered is incorrect.") + +ER3(SEC_ERROR_RETRY_PASSWORD, SEC_ERROR_BASE + 16, +"New password entered incorrectly. Please try again.") + +ER3(SEC_ERROR_NO_NODELOCK, SEC_ERROR_BASE + 17, +"security library: no nodelock.") + +ER3(SEC_ERROR_BAD_DATABASE, SEC_ERROR_BASE + 18, +"security library: bad database.") + +ER3(SEC_ERROR_NO_MEMORY, SEC_ERROR_BASE + 19, +"security library: memory allocation failure.") + +ER3(SEC_ERROR_UNTRUSTED_ISSUER, SEC_ERROR_BASE + 20, +"Peer's certificate issuer has been marked as not trusted by the user.") + +ER3(SEC_ERROR_UNTRUSTED_CERT, SEC_ERROR_BASE + 21, +"Peer's certificate has been marked as not trusted by the user.") + +ER3(SEC_ERROR_DUPLICATE_CERT, (SEC_ERROR_BASE + 22), +"Certificate already exists in your database.") + +ER3(SEC_ERROR_DUPLICATE_CERT_NAME, (SEC_ERROR_BASE + 23), +"Downloaded certificate's name duplicates one already in your database.") + +ER3(SEC_ERROR_ADDING_CERT, (SEC_ERROR_BASE + 24), +"Error adding certificate to database.") + +ER3(SEC_ERROR_FILING_KEY, (SEC_ERROR_BASE + 25), +"Error refiling the key for this certificate.") + +ER3(SEC_ERROR_NO_KEY, (SEC_ERROR_BASE + 26), +"The private key for this certificate cannot be found in key database") + +ER3(SEC_ERROR_CERT_VALID, (SEC_ERROR_BASE + 27), +"This certificate is valid.") + +ER3(SEC_ERROR_CERT_NOT_VALID, (SEC_ERROR_BASE + 28), +"This certificate is not valid.") + +ER3(SEC_ERROR_CERT_NO_RESPONSE, (SEC_ERROR_BASE + 29), +"Cert Library: No Response") + +ER3(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, (SEC_ERROR_BASE + 30), +"The certificate issuer's certificate has expired. Check your system date and time.") + +ER3(SEC_ERROR_CRL_EXPIRED, (SEC_ERROR_BASE + 31), +"The CRL for the certificate's issuer has expired. Update it or check your system data and time.") + +ER3(SEC_ERROR_CRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 32), +"The CRL for the certificate's issuer has an invalid signature.") + +ER3(SEC_ERROR_CRL_INVALID, (SEC_ERROR_BASE + 33), +"New CRL has an invalid format.") + +ER3(SEC_ERROR_EXTENSION_VALUE_INVALID, (SEC_ERROR_BASE + 34), +"Certificate extension value is invalid.") + +ER3(SEC_ERROR_EXTENSION_NOT_FOUND, (SEC_ERROR_BASE + 35), +"Certificate extension not found.") + +ER3(SEC_ERROR_CA_CERT_INVALID, (SEC_ERROR_BASE + 36), +"Issuer certificate is invalid.") + +ER3(SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID, (SEC_ERROR_BASE + 37), +"Certificate path length constraint is invalid.") + +ER3(SEC_ERROR_CERT_USAGES_INVALID, (SEC_ERROR_BASE + 38), +"Certificate usages field is invalid.") + +ER3(SEC_INTERNAL_ONLY, (SEC_ERROR_BASE + 39), +"**Internal ONLY module**") + +ER3(SEC_ERROR_INVALID_KEY, (SEC_ERROR_BASE + 40), +"The key does not support the requested operation.") + +ER3(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, (SEC_ERROR_BASE + 41), +"Certificate contains unknown critical extension.") + +ER3(SEC_ERROR_OLD_CRL, (SEC_ERROR_BASE + 42), +"New CRL is not later than the current one.") + +ER3(SEC_ERROR_NO_EMAIL_CERT, (SEC_ERROR_BASE + 43), +"Not encrypted or signed: you do not yet have an email certificate.") + +ER3(SEC_ERROR_NO_RECIPIENT_CERTS_QUERY, (SEC_ERROR_BASE + 44), +"Not encrypted: you do not have certificates for each of the recipients.") + +ER3(SEC_ERROR_NOT_A_RECIPIENT, (SEC_ERROR_BASE + 45), +"Cannot decrypt: you are not a recipient, or matching certificate and \ +private key not found.") + +ER3(SEC_ERROR_PKCS7_KEYALG_MISMATCH, (SEC_ERROR_BASE + 46), +"Cannot decrypt: key encryption algorithm does not match your certificate.") + +ER3(SEC_ERROR_PKCS7_BAD_SIGNATURE, (SEC_ERROR_BASE + 47), +"Signature verification failed: no signer found, too many signers found, \ +or improper or corrupted data.") + +ER3(SEC_ERROR_UNSUPPORTED_KEYALG, (SEC_ERROR_BASE + 48), +"Unsupported or unknown key algorithm.") + +ER3(SEC_ERROR_DECRYPTION_DISALLOWED, (SEC_ERROR_BASE + 49), +"Cannot decrypt: encrypted using a disallowed algorithm or key size.") + + +/* Fortezza Alerts */ +ER3(XP_SEC_FORTEZZA_BAD_CARD, (SEC_ERROR_BASE + 50), +"Fortezza card has not been properly initialized. \ +Please remove it and return it to your issuer.") + +ER3(XP_SEC_FORTEZZA_NO_CARD, (SEC_ERROR_BASE + 51), +"No Fortezza cards Found") + +ER3(XP_SEC_FORTEZZA_NONE_SELECTED, (SEC_ERROR_BASE + 52), +"No Fortezza card selected") + +ER3(XP_SEC_FORTEZZA_MORE_INFO, (SEC_ERROR_BASE + 53), +"Please select a personality to get more info on") + +ER3(XP_SEC_FORTEZZA_PERSON_NOT_FOUND, (SEC_ERROR_BASE + 54), +"Personality not found") + +ER3(XP_SEC_FORTEZZA_NO_MORE_INFO, (SEC_ERROR_BASE + 55), +"No more information on that Personality") + +ER3(XP_SEC_FORTEZZA_BAD_PIN, (SEC_ERROR_BASE + 56), +"Invalid Pin") + +ER3(XP_SEC_FORTEZZA_PERSON_ERROR, (SEC_ERROR_BASE + 57), +"Couldn't initialize Fortezza personalities.") +/* end fortezza alerts. */ + +ER3(SEC_ERROR_NO_KRL, (SEC_ERROR_BASE + 58), +"No KRL for this site's certificate has been found.") + +ER3(SEC_ERROR_KRL_EXPIRED, (SEC_ERROR_BASE + 59), +"The KRL for this site's certificate has expired.") + +ER3(SEC_ERROR_KRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 60), +"The KRL for this site's certificate has an invalid signature.") + +ER3(SEC_ERROR_REVOKED_KEY, (SEC_ERROR_BASE + 61), +"The key for this site's certificate has been revoked.") + +ER3(SEC_ERROR_KRL_INVALID, (SEC_ERROR_BASE + 62), +"New KRL has an invalid format.") + +ER3(SEC_ERROR_NEED_RANDOM, (SEC_ERROR_BASE + 63), +"security library: need random data.") + +ER3(SEC_ERROR_NO_MODULE, (SEC_ERROR_BASE + 64), +"security library: no security module can perform the requested operation.") + +ER3(SEC_ERROR_NO_TOKEN, (SEC_ERROR_BASE + 65), +"The security card or token does not exist, needs to be initialized, or has been removed.") + +ER3(SEC_ERROR_READ_ONLY, (SEC_ERROR_BASE + 66), +"security library: read-only database.") + +ER3(SEC_ERROR_NO_SLOT_SELECTED, (SEC_ERROR_BASE + 67), +"No slot or token was selected.") + +ER3(SEC_ERROR_CERT_NICKNAME_COLLISION, (SEC_ERROR_BASE + 68), +"A certificate with the same nickname already exists.") + +ER3(SEC_ERROR_KEY_NICKNAME_COLLISION, (SEC_ERROR_BASE + 69), +"A key with the same nickname already exists.") + +ER3(SEC_ERROR_SAFE_NOT_CREATED, (SEC_ERROR_BASE + 70), +"error while creating safe object") + +ER3(SEC_ERROR_BAGGAGE_NOT_CREATED, (SEC_ERROR_BASE + 71), +"error while creating baggage object") + +ER3(XP_JAVA_REMOVE_PRINCIPAL_ERROR, (SEC_ERROR_BASE + 72), +"Couldn't remove the principal") + +ER3(XP_JAVA_DELETE_PRIVILEGE_ERROR, (SEC_ERROR_BASE + 73), +"Couldn't delete the privilege") + +ER3(XP_JAVA_CERT_NOT_EXISTS_ERROR, (SEC_ERROR_BASE + 74), +"This principal doesn't have a certificate") + +ER3(SEC_ERROR_BAD_EXPORT_ALGORITHM, (SEC_ERROR_BASE + 75), +"Required algorithm is not allowed.") + +ER3(SEC_ERROR_EXPORTING_CERTIFICATES, (SEC_ERROR_BASE + 76), +"Error attempting to export certificates.") + +ER3(SEC_ERROR_IMPORTING_CERTIFICATES, (SEC_ERROR_BASE + 77), +"Error attempting to import certificates.") + +ER3(SEC_ERROR_PKCS12_DECODING_PFX, (SEC_ERROR_BASE + 78), +"Unable to import. Decoding error. File not valid.") + +ER3(SEC_ERROR_PKCS12_INVALID_MAC, (SEC_ERROR_BASE + 79), +"Unable to import. Invalid MAC. Incorrect password or corrupt file.") + +ER3(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM, (SEC_ERROR_BASE + 80), +"Unable to import. MAC algorithm not supported.") + +ER3(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE,(SEC_ERROR_BASE + 81), +"Unable to import. Only password integrity and privacy modes supported.") + +ER3(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE, (SEC_ERROR_BASE + 82), +"Unable to import. File structure is corrupt.") + +ER3(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM, (SEC_ERROR_BASE + 83), +"Unable to import. Encryption algorithm not supported.") + +ER3(SEC_ERROR_PKCS12_UNSUPPORTED_VERSION, (SEC_ERROR_BASE + 84), +"Unable to import. File version not supported.") + +ER3(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT,(SEC_ERROR_BASE + 85), +"Unable to import. Incorrect privacy password.") + +ER3(SEC_ERROR_PKCS12_CERT_COLLISION, (SEC_ERROR_BASE + 86), +"Unable to import. Same nickname already exists in database.") + +ER3(SEC_ERROR_USER_CANCELLED, (SEC_ERROR_BASE + 87), +"The user pressed cancel.") + +ER3(SEC_ERROR_PKCS12_DUPLICATE_DATA, (SEC_ERROR_BASE + 88), +"Not imported, already in database.") + +ER3(SEC_ERROR_MESSAGE_SEND_ABORTED, (SEC_ERROR_BASE + 89), +"Message not sent.") + +ER3(SEC_ERROR_INADEQUATE_KEY_USAGE, (SEC_ERROR_BASE + 90), +"Certificate key usage inadequate for attempted operation.") + +ER3(SEC_ERROR_INADEQUATE_CERT_TYPE, (SEC_ERROR_BASE + 91), +"Certificate type not approved for application.") + +ER3(SEC_ERROR_CERT_ADDR_MISMATCH, (SEC_ERROR_BASE + 92), +"Address in signing certificate does not match address in message headers.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY, (SEC_ERROR_BASE + 93), +"Unable to import. Error attempting to import private key.") + +ER3(SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN, (SEC_ERROR_BASE + 94), +"Unable to import. Error attempting to import certificate chain.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME, (SEC_ERROR_BASE + 95), +"Unable to export. Unable to locate certificate or key by nickname.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY, (SEC_ERROR_BASE + 96), +"Unable to export. Private Key could not be located and exported.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_WRITE, (SEC_ERROR_BASE + 97), +"Unable to export. Unable to write the export file.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_READ, (SEC_ERROR_BASE + 98), +"Unable to import. Unable to read the import file.") + +ER3(SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED, (SEC_ERROR_BASE + 99), +"Unable to export. Key database corrupt or deleted.") + +ER3(SEC_ERROR_KEYGEN_FAIL, (SEC_ERROR_BASE + 100), +"Unable to generate public/private key pair.") + +ER3(SEC_ERROR_INVALID_PASSWORD, (SEC_ERROR_BASE + 101), +"Password entered is invalid. Please pick a different one.") + +ER3(SEC_ERROR_RETRY_OLD_PASSWORD, (SEC_ERROR_BASE + 102), +"Old password entered incorrectly. Please try again.") + +ER3(SEC_ERROR_BAD_NICKNAME, (SEC_ERROR_BASE + 103), +"Certificate nickname already in use.") + +ER3(SEC_ERROR_NOT_FORTEZZA_ISSUER, (SEC_ERROR_BASE + 104), +"Peer FORTEZZA chain has a non-FORTEZZA Certificate.") + +/* ER3(SEC_ERROR_UNKNOWN, (SEC_ERROR_BASE + 105), */ + +ER3(SEC_ERROR_JS_INVALID_MODULE_NAME, (SEC_ERROR_BASE + 106), +"Invalid module name.") + +ER3(SEC_ERROR_JS_INVALID_DLL, (SEC_ERROR_BASE + 107), +"Invalid module path/filename") + +ER3(SEC_ERROR_JS_ADD_MOD_FAILURE, (SEC_ERROR_BASE + 108), +"Unable to add module") + +ER3(SEC_ERROR_JS_DEL_MOD_FAILURE, (SEC_ERROR_BASE + 109), +"Unable to delete module") + +ER3(SEC_ERROR_OLD_KRL, (SEC_ERROR_BASE + 110), +"New KRL is not later than the current one.") + +ER3(SEC_ERROR_CKL_CONFLICT, (SEC_ERROR_BASE + 111), +"New CKL has different issuer than current CKL. Delete current CKL.") + +ER3(SEC_ERROR_CERT_NOT_IN_NAME_SPACE, (SEC_ERROR_BASE + 112), +"The Certifying Authority for this certificate is not permitted to issue a \ +certificate with this name.") + +ER3(SEC_ERROR_KRL_NOT_YET_VALID, (SEC_ERROR_BASE + 113), +"The key revocation list for this certificate is not yet valid.") + +ER3(SEC_ERROR_CRL_NOT_YET_VALID, (SEC_ERROR_BASE + 114), +"The certificate revocation list for this certificate is not yet valid.") + +ER3(SEC_ERROR_UNKNOWN_CERT, (SEC_ERROR_BASE + 115), +"The requested certificate could not be found.") + +ER3(SEC_ERROR_UNKNOWN_SIGNER, (SEC_ERROR_BASE + 116), +"The signer's certificate could not be found.") + +ER3(SEC_ERROR_CERT_BAD_ACCESS_LOCATION, (SEC_ERROR_BASE + 117), +"The location for the certificate status server has invalid format.") + +ER3(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE, (SEC_ERROR_BASE + 118), +"The OCSP response cannot be fully decoded; it is of an unknown type.") + +ER3(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE, (SEC_ERROR_BASE + 119), +"The OCSP server returned unexpected/invalid HTTP data.") + +ER3(SEC_ERROR_OCSP_MALFORMED_REQUEST, (SEC_ERROR_BASE + 120), +"The OCSP server found the request to be corrupted or improperly formed.") + +ER3(SEC_ERROR_OCSP_SERVER_ERROR, (SEC_ERROR_BASE + 121), +"The OCSP server experienced an internal error.") + +ER3(SEC_ERROR_OCSP_TRY_SERVER_LATER, (SEC_ERROR_BASE + 122), +"The OCSP server suggests trying again later.") + +ER3(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG, (SEC_ERROR_BASE + 123), +"The OCSP server requires a signature on this request.") + +ER3(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST, (SEC_ERROR_BASE + 124), +"The OCSP server has refused this request as unauthorized.") + +ER3(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, (SEC_ERROR_BASE + 125), +"The OCSP server returned an unrecognizable status.") + +ER3(SEC_ERROR_OCSP_UNKNOWN_CERT, (SEC_ERROR_BASE + 126), +"The OCSP server has no status for the certificate.") + +ER3(SEC_ERROR_OCSP_NOT_ENABLED, (SEC_ERROR_BASE + 127), +"You must enable OCSP before performing this operation.") + +ER3(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER, (SEC_ERROR_BASE + 128), +"You must set the OCSP default responder before performing this operation.") + +ER3(SEC_ERROR_OCSP_MALFORMED_RESPONSE, (SEC_ERROR_BASE + 129), +"The response from the OCSP server was corrupted or improperly formed.") + +ER3(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE, (SEC_ERROR_BASE + 130), +"The signer of the OCSP response is not authorized to give status for \ +this certificate.") + +ER3(SEC_ERROR_OCSP_FUTURE_RESPONSE, (SEC_ERROR_BASE + 131), +"The OCSP response is not yet valid (contains a date in the future).") + +ER3(SEC_ERROR_OCSP_OLD_RESPONSE, (SEC_ERROR_BASE + 132), +"The OCSP response contains out-of-date information.") diff --git a/security/nss/cmd/SSLsample/SSLerrs.h b/security/nss/cmd/SSLsample/SSLerrs.h new file mode 100644 index 000000000..06803b849 --- /dev/null +++ b/security/nss/cmd/SSLsample/SSLerrs.h @@ -0,0 +1,366 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* SSL-specific security error codes */ +/* caller must include "sslerr.h" */ + +ER3(SSL_ERROR_EXPORT_ONLY_SERVER, SSL_ERROR_BASE + 0, +"Unable to communicate securely. Peer does not support high-grade encryption.") + +ER3(SSL_ERROR_US_ONLY_SERVER, SSL_ERROR_BASE + 1, +"Unable to communicate securely. Peer requires high-grade encryption which is not supported.") + +ER3(SSL_ERROR_NO_CYPHER_OVERLAP, SSL_ERROR_BASE + 2, +"Cannot communicate securely with peer: no common encryption algorithm(s).") + +ER3(SSL_ERROR_NO_CERTIFICATE, SSL_ERROR_BASE + 3, +"Unable to find the certificate or key necessary for authentication.") + +ER3(SSL_ERROR_BAD_CERTIFICATE, SSL_ERROR_BASE + 4, +"Unable to communicate securely with peer: peers's certificate was rejected.") + +/* unused (SSL_ERROR_BASE + 5),*/ + +ER3(SSL_ERROR_BAD_CLIENT, SSL_ERROR_BASE + 6, +"The server has encountered bad data from the client.") + +ER3(SSL_ERROR_BAD_SERVER, SSL_ERROR_BASE + 7, +"The client has encountered bad data from the server.") + +ER3(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE, SSL_ERROR_BASE + 8, +"Unsupported certificate type.") + +ER3(SSL_ERROR_UNSUPPORTED_VERSION, SSL_ERROR_BASE + 9, +"Peer using unsupported version of security protocol.") + +/* unused (SSL_ERROR_BASE + 10),*/ + +ER3(SSL_ERROR_WRONG_CERTIFICATE, SSL_ERROR_BASE + 11, +"Client authentication failed: private key in key database does not match public key in certificate database.") + +ER3(SSL_ERROR_BAD_CERT_DOMAIN, SSL_ERROR_BASE + 12, +"Unable to communicate securely with peer: requested domain name does not match the server's certificate.") + +/* SSL_ERROR_POST_WARNING (SSL_ERROR_BASE + 13), + defined in sslerr.h +*/ + +ER3(SSL_ERROR_SSL2_DISABLED, (SSL_ERROR_BASE + 14), +"Peer only supports SSL version 2, which is locally disabled.") + + +ER3(SSL_ERROR_BAD_MAC_READ, (SSL_ERROR_BASE + 15), +"SSL received a record with an incorrect Message Authentication Code.") + +ER3(SSL_ERROR_BAD_MAC_ALERT, (SSL_ERROR_BASE + 16), +"SSL peer reports incorrect Message Authentication Code.") + +ER3(SSL_ERROR_BAD_CERT_ALERT, (SSL_ERROR_BASE + 17), +"SSL peer cannot verify your certificate.") + +ER3(SSL_ERROR_REVOKED_CERT_ALERT, (SSL_ERROR_BASE + 18), +"SSL peer rejected your certificate as revoked.") + +ER3(SSL_ERROR_EXPIRED_CERT_ALERT, (SSL_ERROR_BASE + 19), +"SSL peer rejected your certificate as expired.") + +ER3(SSL_ERROR_SSL_DISABLED, (SSL_ERROR_BASE + 20), +"Cannot connect: SSL is disabled.") + +ER3(SSL_ERROR_FORTEZZA_PQG, (SSL_ERROR_BASE + 21), +"Cannot connect: SSL peer is in another FORTEZZA domain.") + + +ER3(SSL_ERROR_UNKNOWN_CIPHER_SUITE , (SSL_ERROR_BASE + 22), +"An unknown SSL cipher suite has been requested.") + +ER3(SSL_ERROR_NO_CIPHERS_SUPPORTED , (SSL_ERROR_BASE + 23), +"No cipher suites are present and enabled in this program.") + +ER3(SSL_ERROR_BAD_BLOCK_PADDING , (SSL_ERROR_BASE + 24), +"SSL received a record with bad block padding.") + +ER3(SSL_ERROR_RX_RECORD_TOO_LONG , (SSL_ERROR_BASE + 25), +"SSL received a record that exceeded the maximum permissible length.") + +ER3(SSL_ERROR_TX_RECORD_TOO_LONG , (SSL_ERROR_BASE + 26), +"SSL attempted to send a record that exceeded the maximum permissible length.") + +/* + * Received a malformed (too long or short or invalid content) SSL handshake. + */ +ER3(SSL_ERROR_RX_MALFORMED_HELLO_REQUEST , (SSL_ERROR_BASE + 27), +"SSL received a malformed Hello Request handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO , (SSL_ERROR_BASE + 28), +"SSL received a malformed Client Hello handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_SERVER_HELLO , (SSL_ERROR_BASE + 29), +"SSL received a malformed Server Hello handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CERTIFICATE , (SSL_ERROR_BASE + 30), +"SSL received a malformed Certificate handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH , (SSL_ERROR_BASE + 31), +"SSL received a malformed Server Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CERT_REQUEST , (SSL_ERROR_BASE + 32), +"SSL received a malformed Certificate Request handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_HELLO_DONE , (SSL_ERROR_BASE + 33), +"SSL received a malformed Server Hello Done handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CERT_VERIFY , (SSL_ERROR_BASE + 34), +"SSL received a malformed Certificate Verify handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH , (SSL_ERROR_BASE + 35), +"SSL received a malformed Client Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_FINISHED , (SSL_ERROR_BASE + 36), +"SSL received a malformed Finished handshake message.") + +/* + * Received a malformed (too long or short) SSL record. + */ +ER3(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER , (SSL_ERROR_BASE + 37), +"SSL received a malformed Change Cipher Spec record.") + +ER3(SSL_ERROR_RX_MALFORMED_ALERT , (SSL_ERROR_BASE + 38), +"SSL received a malformed Alert record.") + +ER3(SSL_ERROR_RX_MALFORMED_HANDSHAKE , (SSL_ERROR_BASE + 39), +"SSL received a malformed Handshake record.") + +ER3(SSL_ERROR_RX_MALFORMED_APPLICATION_DATA , (SSL_ERROR_BASE + 40), +"SSL received a malformed Application Data record.") + +/* + * Received an SSL handshake that was inappropriate for the state we're in. + * E.g. Server received message from server, or wrong state in state machine. + */ +ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST , (SSL_ERROR_BASE + 41), +"SSL received an unexpected Hello Request handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO , (SSL_ERROR_BASE + 42), +"SSL received an unexpected Client Hello handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO , (SSL_ERROR_BASE + 43), +"SSL received an unexpected Server Hello handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CERTIFICATE , (SSL_ERROR_BASE + 44), +"SSL received an unexpected Certificate handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH , (SSL_ERROR_BASE + 45), +"SSL received an unexpected Server Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST , (SSL_ERROR_BASE + 46), +"SSL received an unexpected Certificate Request handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE , (SSL_ERROR_BASE + 47), +"SSL received an unexpected Server Hello Done handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY , (SSL_ERROR_BASE + 48), +"SSL received an unexpected Certificate Verify handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH , (SSL_ERROR_BASE + 49), +"SSL received an unexpected Cllient Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_FINISHED , (SSL_ERROR_BASE + 50), +"SSL received an unexpected Finished handshake message.") + +/* + * Received an SSL record that was inappropriate for the state we're in. + */ +ER3(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER , (SSL_ERROR_BASE + 51), +"SSL received an unexpected Change Cipher Spec record.") + +ER3(SSL_ERROR_RX_UNEXPECTED_ALERT , (SSL_ERROR_BASE + 52), +"SSL received an unexpected Alert record.") + +ER3(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE , (SSL_ERROR_BASE + 53), +"SSL received an unexpected Handshake record.") + +ER3(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA, (SSL_ERROR_BASE + 54), +"SSL received an unexpected Application Data record.") + +/* + * Received record/message with unknown discriminant. + */ +ER3(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE , (SSL_ERROR_BASE + 55), +"SSL received a record with an unknown content type.") + +ER3(SSL_ERROR_RX_UNKNOWN_HANDSHAKE , (SSL_ERROR_BASE + 56), +"SSL received a handshake message with an unknown message type.") + +ER3(SSL_ERROR_RX_UNKNOWN_ALERT , (SSL_ERROR_BASE + 57), +"SSL received an alert record with an unknown alert description.") + +/* + * Received an alert reporting what we did wrong. (more alerts above) + */ +ER3(SSL_ERROR_CLOSE_NOTIFY_ALERT , (SSL_ERROR_BASE + 58), +"SSL peer has closed this connection.") + +ER3(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT , (SSL_ERROR_BASE + 59), +"SSL peer was not expecting a handshake message it received.") + +ER3(SSL_ERROR_DECOMPRESSION_FAILURE_ALERT , (SSL_ERROR_BASE + 60), +"SSL peer was unable to succesfully decompress an SSL record it received.") + +ER3(SSL_ERROR_HANDSHAKE_FAILURE_ALERT , (SSL_ERROR_BASE + 61), +"SSL peer was unable to negotiate an acceptable set of security parameters.") + +ER3(SSL_ERROR_ILLEGAL_PARAMETER_ALERT , (SSL_ERROR_BASE + 62), +"SSL peer rejected a handshake message for unacceptable content.") + +ER3(SSL_ERROR_UNSUPPORTED_CERT_ALERT , (SSL_ERROR_BASE + 63), +"SSL peer does not support certificates of the type it received.") + +ER3(SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT , (SSL_ERROR_BASE + 64), +"SSL peer had some unspecified issue with the certificate it received.") + + +ER3(SSL_ERROR_GENERATE_RANDOM_FAILURE , (SSL_ERROR_BASE + 65), +"SSL experienced a failure of its random number generator.") + +ER3(SSL_ERROR_SIGN_HASHES_FAILURE , (SSL_ERROR_BASE + 66), +"Unable to digitally sign data required to verify your certificate.") + +ER3(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE , (SSL_ERROR_BASE + 67), +"SSL was unable to extract the public key from the peer's certificate.") + +ER3(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE , (SSL_ERROR_BASE + 68), +"Unspecified failure while processing SSL Server Key Exchange handshake.") + +ER3(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE , (SSL_ERROR_BASE + 69), +"Unspecified failure while processing SSL Client Key Exchange handshake.") + +ER3(SSL_ERROR_ENCRYPTION_FAILURE , (SSL_ERROR_BASE + 70), +"Bulk data encryption algorithm failed in selected cipher suite.") + +ER3(SSL_ERROR_DECRYPTION_FAILURE , (SSL_ERROR_BASE + 71), +"Bulk data decryption algorithm failed in selected cipher suite.") + +ER3(SSL_ERROR_SOCKET_WRITE_FAILURE , (SSL_ERROR_BASE + 72), +"Attempt to write encrypted data to underlying socket failed.") + +ER3(SSL_ERROR_MD5_DIGEST_FAILURE , (SSL_ERROR_BASE + 73), +"MD5 digest function failed.") + +ER3(SSL_ERROR_SHA_DIGEST_FAILURE , (SSL_ERROR_BASE + 74), +"SHA-1 digest function failed.") + +ER3(SSL_ERROR_MAC_COMPUTATION_FAILURE , (SSL_ERROR_BASE + 75), +"MAC computation failed.") + +ER3(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE , (SSL_ERROR_BASE + 76), +"Failure to create Symmetric Key context.") + +ER3(SSL_ERROR_SYM_KEY_UNWRAP_FAILURE , (SSL_ERROR_BASE + 77), +"Failure to unwrap the Symmetric key in Client Key Exchange message.") + +ER3(SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED , (SSL_ERROR_BASE + 78), +"SSL Server attempted to use domestic-grade public key with export cipher suite.") + +ER3(SSL_ERROR_IV_PARAM_FAILURE , (SSL_ERROR_BASE + 79), +"PKCS11 code failed to translate an IV into a param.") + +ER3(SSL_ERROR_INIT_CIPHER_SUITE_FAILURE , (SSL_ERROR_BASE + 80), +"Failed to initialize the selected cipher suite.") + +ER3(SSL_ERROR_SESSION_KEY_GEN_FAILURE , (SSL_ERROR_BASE + 81), +"Client failed to generate session keys for SSL session.") + +ER3(SSL_ERROR_NO_SERVER_KEY_FOR_ALG , (SSL_ERROR_BASE + 82), +"Server has no key for the attempted key exchange algorithm.") + +ER3(SSL_ERROR_TOKEN_INSERTION_REMOVAL , (SSL_ERROR_BASE + 83), +"PKCS#11 token was inserted or removed while operation was in progress.") + +ER3(SSL_ERROR_TOKEN_SLOT_NOT_FOUND , (SSL_ERROR_BASE + 84), +"No PKCS#11 token could be found to do a required operation.") + +ER3(SSL_ERROR_NO_COMPRESSION_OVERLAP , (SSL_ERROR_BASE + 85), +"Cannot communicate securely with peer: no common compression algorithm(s).") + +ER3(SSL_ERROR_HANDSHAKE_NOT_COMPLETED , (SSL_ERROR_BASE + 86), +"Cannot initiate another SSL handshake until current handshake is complete.") + +ER3(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE , (SSL_ERROR_BASE + 87), +"Received incorrect handshakes hash values from peer.") + +ER3(SSL_ERROR_CERT_KEA_MISMATCH , (SSL_ERROR_BASE + 88), +"The certificate provided cannot be used with the selected key exchange algorithm.") + +ER3(SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA , (SSL_ERROR_BASE + 89), +"No certificate authority is trusted for SSL client authentication.") + +ER3(SSL_ERROR_SESSION_NOT_FOUND , (SSL_ERROR_BASE + 90), +"Client's SSL session ID not found in server's session cache.") + +ER3(SSL_ERROR_DECRYPTION_FAILED_ALERT , (SSL_ERROR_BASE + 91), +"Peer was unable to decrypt an SSL record it received.") + +ER3(SSL_ERROR_RECORD_OVERFLOW_ALERT , (SSL_ERROR_BASE + 92), +"Peer received an SSL record that was longer than is permitted.") + +ER3(SSL_ERROR_UNKNOWN_CA_ALERT , (SSL_ERROR_BASE + 93), +"Peer does not recognize and trust the CA that issued your certificate.") + +ER3(SSL_ERROR_ACCESS_DENIED_ALERT , (SSL_ERROR_BASE + 94), +"Peer received a valid certificate, but access was denied.") + +ER3(SSL_ERROR_DECODE_ERROR_ALERT , (SSL_ERROR_BASE + 95), +"Peer could not decode an SSL handshake message.") + +ER3(SSL_ERROR_DECRYPT_ERROR_ALERT , (SSL_ERROR_BASE + 96), +"Peer reports failure of signature verification or key exchange.") + +ER3(SSL_ERROR_EXPORT_RESTRICTION_ALERT , (SSL_ERROR_BASE + 97), +"Peer reports negotiation not in compliance with export regulations.") + +ER3(SSL_ERROR_PROTOCOL_VERSION_ALERT , (SSL_ERROR_BASE + 98), +"Peer reports incompatible or unsupported protocol version.") + +ER3(SSL_ERROR_INSUFFICIENT_SECURITY_ALERT , (SSL_ERROR_BASE + 99), +"Server requires ciphers more secure than those supported by client.") + +ER3(SSL_ERROR_INTERNAL_ERROR_ALERT , (SSL_ERROR_BASE + 100), +"Peer reports it experienced an internal error.") + +ER3(SSL_ERROR_USER_CANCELED_ALERT , (SSL_ERROR_BASE + 101), +"Peer user canceled handshake.") + +ER3(SSL_ERROR_NO_RENEGOTIATION_ALERT , (SSL_ERROR_BASE + 102), +"Peer does not permit renegotiation of SSL security parameters.") + diff --git a/security/nss/cmd/SSLsample/client.c b/security/nss/cmd/SSLsample/client.c new file mode 100644 index 000000000..e5cd1013c --- /dev/null +++ b/security/nss/cmd/SSLsample/client.c @@ -0,0 +1,453 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/**************************************************************************** + * SSL client program that sets up a connection to SSL server, transmits * + * some data and then reads the reply * + ****************************************************************************/ + +#include <stdio.h> +#include <string.h> + +#if defined(XP_UNIX) +#include <unistd.h> +#endif + +#include "prerror.h" + +#include "pk11func.h" +#include "secitem.h" + + +#include <stdlib.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> + +#include "nspr.h" +#include "plgetopt.h" +#include "prio.h" +#include "prnetdb.h" +#include "nss.h" + +#include "sslsample.h" + +#define RD_BUF_SIZE (60 * 1024) + +extern int ssl2CipherSuites[]; +extern int ssl3CipherSuites[]; + +GlobalThreadMgr threadMGR; +char *certNickname = NULL; +char *hostName = NULL; +char *password = NULL; +unsigned short port = 0; + +static void +Usage(const char *progName) +{ + fprintf(stderr, + "Usage: %s [-n rsa_nickname] [-p port] [-d dbdir] [-c connections]\n" + " [-w dbpasswd] [-C cipher(s)] hostname\n", + progName); + exit(1); +} + +PRFileDesc * +setupSSLSocket(PRNetAddr *addr) +{ + PRFileDesc *tcpSocket; + PRFileDesc *sslSocket; + PRSocketOptionData socketOption; + PRStatus prStatus; + SECStatus secStatus; + +#if 0 +retry: +#endif + + tcpSocket = PR_NewTCPSocket(); + if (tcpSocket == NULL) { + errWarn("PR_NewTCPSocket"); + } + + /* Make the socket blocking. */ + socketOption.option = PR_SockOpt_Nonblocking; + socketOption.value.non_blocking = PR_FALSE; + + prStatus = PR_SetSocketOption(tcpSocket, &socketOption); + if (prStatus != PR_SUCCESS) { + errWarn("PR_SetSocketOption"); + goto loser; + } + +#if 0 + /* Verify that a connection can be made to the socket. */ + prStatus = PR_Connect(tcpSocket, addr, PR_INTERVAL_NO_TIMEOUT); + if (prStatus != PR_SUCCESS) { + PRErrorCode err = PR_GetError(); + if (err == PR_CONNECT_REFUSED_ERROR) { + PR_Close(tcpSocket); + PR_Sleep(PR_MillisecondsToInterval(10)); + fprintf(stderr, "Connection to port refused, retrying.\n"); + goto retry; + } + errWarn("PR_Connect"); + goto loser; + } +#endif + + /* Import the socket into the SSL layer. */ + sslSocket = SSL_ImportFD(NULL, tcpSocket); + if (!sslSocket) { + errWarn("SSL_ImportFD"); + goto loser; + } + + /* Set configuration options. */ + secStatus = SSL_OptionSet(sslSocket, SSL_SECURITY, PR_TRUE); + if (secStatus != SECSuccess) { + errWarn("SSL_OptionSet:SSL_SECURITY"); + goto loser; + } + + secStatus = SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); + if (secStatus != SECSuccess) { + errWarn("SSL_OptionSet:SSL_HANDSHAKE_AS_CLIENT"); + goto loser; + } + + /* Set SSL callback routines. */ + secStatus = SSL_GetClientAuthDataHook(sslSocket, + (SSLGetClientAuthData)myGetClientAuthData, + (void *)certNickname); + if (secStatus != SECSuccess) { + errWarn("SSL_GetClientAuthDataHook"); + goto loser; + } + + secStatus = SSL_AuthCertificateHook(sslSocket, + (SSLAuthCertificate)myAuthCertificate, + (void *)CERT_GetDefaultCertDB()); + if (secStatus != SECSuccess) { + errWarn("SSL_AuthCertificateHook"); + goto loser; + } + + secStatus = SSL_BadCertHook(sslSocket, + (SSLBadCertHandler)myBadCertHandler, NULL); + if (secStatus != SECSuccess) { + errWarn("SSL_BadCertHook"); + goto loser; + } + + secStatus = SSL_HandshakeCallback(sslSocket, + (SSLHandshakeCallback)myHandshakeCallback, + NULL); + if (secStatus != SECSuccess) { + errWarn("SSL_HandshakeCallback"); + goto loser; + } + + return sslSocket; + +loser: + + PR_Close(tcpSocket); + return NULL; +} + + +const char requestString[] = {"GET /testfile HTTP/1.0\r\n\r\n" }; + +SECStatus +handle_connection(PRFileDesc *sslSocket, int connection) +{ + int countRead = 0; + PRInt32 numBytes; + char *readBuffer; + + readBuffer = PORT_Alloc(RD_BUF_SIZE); + if (!readBuffer) { + exitErr("PORT_Alloc"); + } + + /* compose the http request here. */ + + numBytes = PR_Write(sslSocket, requestString, strlen(requestString)); + if (numBytes <= 0) { + errWarn("PR_Write"); + PR_Free(readBuffer); + readBuffer = NULL; + return SECFailure; + } + + /* read until EOF */ + while (PR_TRUE) { + numBytes = PR_Read(sslSocket, readBuffer, RD_BUF_SIZE); + if (numBytes == 0) { + break; /* EOF */ + } + if (numBytes < 0) { + errWarn("PR_Read"); + break; + } + countRead += numBytes; + fprintf(stderr, "***** Connection %d read %d bytes (%d total).\n", + connection, numBytes, countRead ); + readBuffer[numBytes] = '\0'; + fprintf(stderr, "************\n%s\n************\n", readBuffer); + } + + printSecurityInfo(sslSocket); + + PR_Free(readBuffer); + readBuffer = NULL; + + /* Caller closes the socket. */ + + fprintf(stderr, + "***** Connection %d read %d bytes total.\n", + connection, countRead); + + return SECSuccess; /* success */ +} + +/* one copy of this function is launched in a separate thread for each +** connection to be made. +*/ +SECStatus +do_connects(void *a, int connection) +{ + PRNetAddr *addr = (PRNetAddr *)a; + PRFileDesc *sslSocket; + PRHostEnt hostEntry; + char buffer[PR_NETDB_BUF_SIZE]; + PRStatus prStatus; + PRIntn hostenum; + SECStatus secStatus; + + /* Set up SSL secure socket. */ + sslSocket = setupSSLSocket(addr); + if (sslSocket == NULL) { + errWarn("setupSSLSocket"); + return SECFailure; + } + + secStatus = SSL_SetPKCS11PinArg(sslSocket, password); + if (secStatus != SECSuccess) { + errWarn("SSL_SetPKCS11PinArg"); + return secStatus; + } + + secStatus = SSL_SetURL(sslSocket, hostName); + if (secStatus != SECSuccess) { + errWarn("SSL_SetURL"); + return secStatus; + } + + /* Prepare and setup network connection. */ + prStatus = PR_GetHostByName(hostName, buffer, sizeof(buffer), &hostEntry); + if (prStatus != PR_SUCCESS) { + errWarn("PR_GetHostByName"); + return SECFailure; + } + + hostenum = PR_EnumerateHostEnt(0, &hostEntry, port, addr); + if (hostenum == -1) { + errWarn("PR_EnumerateHostEnt"); + return SECFailure; + } + + prStatus = PR_Connect(sslSocket, addr, PR_INTERVAL_NO_TIMEOUT); + if (prStatus != PR_SUCCESS) { + errWarn("PR_Connect"); + return SECFailure; + } + + /* Established SSL connection, ready to send data. */ +#if 0 + secStatus = SSL_ForceHandshake(sslSocket); + if (secStatus != SECSuccess) { + errWarn("SSL_ForceHandshake"); + return secStatus; + } +#endif + + secStatus = SSL_ResetHandshake(sslSocket, /* asServer */ PR_FALSE); + if (secStatus != SECSuccess) { + errWarn("SSL_ResetHandshake"); + prStatus = PR_Close(sslSocket); + if (prStatus != PR_SUCCESS) { + errWarn("PR_Close"); + } + return secStatus; + } + + secStatus = handle_connection(sslSocket, connection); + if (secStatus != SECSuccess) { + errWarn("handle_connection"); + return secStatus; + } + + PR_Close(sslSocket); + return SECSuccess; +} + +void +client_main(unsigned short port, + int connections, + const char * hostName) +{ + int i; + SECStatus secStatus; + PRStatus prStatus; + PRInt32 rv; + PRNetAddr addr; + PRHostEnt hostEntry; + char buffer[256]; + + /* Setup network connection. */ + prStatus = PR_GetHostByName(hostName, buffer, 256, &hostEntry); + if (prStatus != PR_SUCCESS) { + exitErr("PR_GetHostByName"); + } + + rv = PR_EnumerateHostEnt(0, &hostEntry, port, &addr); + if (rv < 0) { + exitErr("PR_EnumerateHostEnt"); + } + + secStatus = launch_thread(&threadMGR, do_connects, &addr, 1); + if (secStatus != SECSuccess) { + exitErr("launch_thread"); + } + + if (connections > 1) { + /* wait for the first connection to terminate, then launch the rest. */ + reap_threads(&threadMGR); + /* Start up the connections */ + for (i = 2; i <= connections; ++i) { + secStatus = launch_thread(&threadMGR, do_connects, &addr, i); + if (secStatus != SECSuccess) { + errWarn("launch_thread"); + } + } + } + + reap_threads(&threadMGR); + destroy_thread_data(&threadMGR); +} + +int +main(int argc, char **argv) +{ + char * certDir = "."; + char * progName = NULL; + int connections = 1; + char * cipherString = NULL; + SECStatus secStatus; + PLOptState * optstate; + PLOptStatus status; + + /* Call the NSPR initialization routines */ + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + + progName = PL_strdup(argv[0]); + + hostName = NULL; + optstate = PL_CreateOptState(argc, argv, "C:c:d:n:p:w:"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch(optstate->option) { + case 'C' : cipherString = PL_strdup(optstate->value); break; + case 'c' : connections = PORT_Atoi(optstate->value); break; + case 'd' : certDir = PL_strdup(optstate->value); break; + case 'n' : certNickname = PL_strdup(optstate->value); break; + case 'p' : port = PORT_Atoi(optstate->value); break; + case 'w' : password = PL_strdup(optstate->value); break; + case '\0': hostName = PL_strdup(optstate->value); break; + default : Usage(progName); + } + } + + if (port == 0 || hostName == NULL) + Usage(progName); + + if (certDir == NULL) { + certDir = PR_smprintf("%s/.netscape", getenv("HOME")); + } + + /* Set our password function callback. */ + PK11_SetPasswordFunc(myPasswd); + + /* Initialize the NSS libraries. */ + secStatus = NSS_Init(certDir); + if (secStatus != SECSuccess) { + exitErr("NSS_Init"); + } + + /* All cipher suites except RSA_NULL_MD5 are enabled by Domestic Policy. */ + NSS_SetDomesticPolicy(); + SSL_CipherPrefSetDefault(SSL_RSA_WITH_NULL_MD5, PR_TRUE); + + /* all the SSL2 and SSL3 cipher suites are enabled by default. */ + if (cipherString) { + int ndx; + + /* disable all the ciphers, then enable the ones we want. */ + disableAllSSLCiphers(); + + while (0 != (ndx = *cipherString++)) { + int *cptr; + int cipher; + + if (! isalpha(ndx)) + Usage(progName); + cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites; + for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; ) + /* do nothing */; + if (cipher) { + SSL_CipherPrefSetDefault(cipher, PR_TRUE); + } + } + } + + client_main(port, connections, hostName); + + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + PR_Cleanup(); + return 0; +} + diff --git a/security/nss/cmd/SSLsample/client.mn b/security/nss/cmd/SSLsample/client.mn new file mode 100644 index 000000000..5c7fa3d7c --- /dev/null +++ b/security/nss/cmd/SSLsample/client.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +MODULE = nss + +EXPORTS = + +CSRCS = client.c \ + sslsample.c \ + $(NULL) + +PROGRAM = client + +REQUIRES = dbm + +IMPORTS = nss/lib/nss + +DEFINES = -DNSPR20 + diff --git a/security/nss/cmd/SSLsample/gencerts b/security/nss/cmd/SSLsample/gencerts new file mode 100755 index 000000000..80be66a43 --- /dev/null +++ b/security/nss/cmd/SSLsample/gencerts @@ -0,0 +1,79 @@ +#!/bin/sh +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# +# +# Script to generate sample db files neccessary for SSL. + +# Directory for db's, use in all subsequent -d flags. +rm -rf SampleCertDBs +mkdir SampleCertDBs + +# Password to use. +echo sample > passfile + +# Generate the db files, using the above password. +certutil -N -d SampleCertDBs -f passfile + +# Generate the CA cert. This cert is self-signed and only useful for +# test purposes. Set the trust bits to allow it to sign SSL client/server +# certs. +certutil -S -n SampleRootCA -x -t "CTu,CTu,CTu" \ + -s "CN=My Sample Root CA, O=My Organization" \ + -m 25000 -o ./SampleCertDBs/SampleRootCA.crt \ + -d SampleCertDBs -f passfile + +# Generate the server cert. This cert is signed by the CA cert generated +# above. The CN must be hostname.domain.[com|org|net|...]. +certutil -S -n SampleSSLServerCert -c SampleRootCA -t "u,u,u" \ + -s "CN=$HOSTNAME.$MYDOMAIN, O=$HOSTNAME Corp." \ + -m 25001 -o ./SampleCertDBs/SampleSSLServer.crt \ + -d SampleCertDBs -f passfile + +# Generate the client cert. This cert is signed by the CA cert generated +# above. +certutil -S -n SampleSSLClientCert -c SampleRootCA -t "u,u,u" \ + -s "CN=My Client Cert, O=Client Organization" \ + -m 25002 -o ./SampleCertDBs/SampleSSLClient.crt \ + -d SampleCertDBs -f passfile + +# Verify the certificates. +certutil -V -u V -n SampleSSLServerCert -d SampleCertDBs +certutil -V -u C -n SampleSSLClientCert -d SampleCertDBs + +# Remove unneccessary files. +rm -f passfile +rm -f tempcert* + +# You are now ready to run your client/server! Example command lines: +# server -n SampleSSLServerCert -p 8080 -d SampleCertDBs -w sample -c e -R +# client -n SampleSSLClientCert -p 8080 -d SampleCertDBs -w sample -c 2 trane.mcom.com diff --git a/security/nss/cmd/SSLsample/make.client b/security/nss/cmd/SSLsample/make.client new file mode 100644 index 000000000..3dd7705e3 --- /dev/null +++ b/security/nss/cmd/SSLsample/make.client @@ -0,0 +1,78 @@ +#! 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 client.mn + +####################################################################### +# (2) Include "global" configuration information. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +#include $(CORE_DEPTH)/$(MODULE)/config/config.mk + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +#CC = cc + + diff --git a/security/nss/cmd/SSLsample/make.server b/security/nss/cmd/SSLsample/make.server new file mode 100644 index 000000000..7969df798 --- /dev/null +++ b/security/nss/cmd/SSLsample/make.server @@ -0,0 +1,77 @@ +#! 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 server.mn + +####################################################################### +# (2) Include "global" configuration information. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +#include $(CORE_DEPTH)/$(MODULE)/config/config.mk + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + + diff --git a/security/nss/cmd/SSLsample/nmakefile95.nss b/security/nss/cmd/SSLsample/nmakefile95.nss new file mode 100755 index 000000000..5684478cd --- /dev/null +++ b/security/nss/cmd/SSLsample/nmakefile95.nss @@ -0,0 +1,60 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +# NSS 2.6.2 Sample Win95 Makefile +# +# +# This nmake file will build server.c and client.c on Windows 95. +# + +DEFINES=-D_X86_ -DXP_PC -UDEBUG -U_DEBUG -DNDEBUG -DWIN32 -D_WINDOWS + +INCPATH=/I. /I..\include\dbm /I..\include\nspr /I..\include\security + +LIBS=nss.lib ssl.lib pkcs7.lib pkcs12.lib secmod.lib cert.lib key.lib crypto.lib secutil.lib hash.lib dbm.lib libplc3.lib libplds3.lib libnspr3.lib wsock32.lib + +CFLAGS=-O2 -MD -W3 -nologo + +CC=cl + +LDOPTIONS=/link /LIBPATH:..\lib /nodefaultlib:libcd.lib /subsystem:console + +server: + $(CC) $(CFLAGS) $(INCPATH) /Feserver server.c getopt.c $(LIBS) $(DEFINES) $(LDOPTIONS) + +client: + $(CC) $(CFLAGS) $(INCPATH) /Feclient client.c getopt.c $(LIBS) $(DEFINES) $(LDOPTIONS) + +clean: + del /S server.exe client.exe server.lib server.exp client.lib client.exp server.obj client.obj getopt.obj + diff --git a/security/nss/cmd/SSLsample/nmakefilent.nss b/security/nss/cmd/SSLsample/nmakefilent.nss new file mode 100755 index 000000000..9d2d1ccc4 --- /dev/null +++ b/security/nss/cmd/SSLsample/nmakefilent.nss @@ -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. +# + +# NSS 2.6.2 Sample NT Makefile +# +# +# This nmake file will build server.c and client.c on Windows NT 4 SP3. +# + +DEFINES=-D_X86_ -GT -DWINNT -DXP_PC -UDEBUG -U_DEBUG -DNDEBUG -DWIN32 -D_WINDOWS +INCPATH=-I. -I..\include\dbm -I..\include\nspr -I..\include\security + +LIBS=nss.lib ssl.lib pkcs7.lib pkcs12.lib secmod.lib cert.lib key.lib crypto.lib secutil.lib hash.lib dbm.lib libplc3.lib libplds3.lib libnspr3.lib wsock32.lib + +CFLAGS=-O2 -MD -W3 -nologo + +CC=cl + +LDOPTIONS=/link /LIBPATH:..\lib /nodefaultlib:libcd.lib /subsystem:console + +server: + $(CC) $(CFLAGS) /Feserver server.c getopt.c $(LIBS) $(DEFINES) $(INCPATH) $(LDOPTIONS) + +client: + $(CC) $(CFLAGS) /Feclient client.c getopt.c $(LIBS) $(DEFINES) $(INCPATH) $(LDOPTIONS) + +clean: + del /S server.exe client.exe server.lib server.exp client.lib client.exp server.obj client.obj getopt.obj + diff --git a/security/nss/cmd/SSLsample/server.c b/security/nss/cmd/SSLsample/server.c new file mode 100644 index 000000000..08c20a5a4 --- /dev/null +++ b/security/nss/cmd/SSLsample/server.c @@ -0,0 +1,822 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/**************************************************************************** + * SSL server program listens on a port, accepts client connection, reads * + * request and responds to it * + ****************************************************************************/ + +/* Generic header files */ + +#include <stdio.h> +#include <string.h> + +/* NSPR header files */ + +#include "nspr.h" +#include "plgetopt.h" +#include "prerror.h" +#include "prnetdb.h" + +/* NSS header files */ + +#include "pk11func.h" +#include "secitem.h" +#include "ssl.h" +#include "certt.h" +#include "nss.h" +#include "secrng.h" +#include "secder.h" +#include "key.h" +#include "sslproto.h" + +/* Custom header files */ + +#include "sslsample.h" + +#ifndef PORT_Sprintf +#define PORT_Sprintf sprintf +#endif + +#define REQUEST_CERT_ONCE 1 +#define REQUIRE_CERT_ONCE 2 +#define REQUEST_CERT_ALL 3 +#define REQUIRE_CERT_ALL 4 + +/* Global variables */ +GlobalThreadMgr threadMGR; +char *password = NULL; +CERTCertificate *cert = NULL; +SECKEYPrivateKey *privKey = NULL; +int stopping; + +static void +Usage(const char *progName) +{ + fprintf(stderr, + +"Usage: %s -n rsa_nickname -p port [-3RFrf] [-w password]\n" +" [-c ciphers] [-d dbdir] \n" +"-3 means disable SSL v3\n" +"-r means request certificate on first handshake.\n" +"-f means require certificate on first handshake.\n" +"-R means request certificate on all handshakes.\n" +"-F means require certificate on all handshakes.\n" +"-c ciphers Letter(s) chosen from the following list\n" +"A SSL2 RC4 128 WITH MD5\n" +"B SSL2 RC4 128 EXPORT40 WITH MD5\n" +"C SSL2 RC2 128 CBC WITH MD5\n" +"D SSL2 RC2 128 CBC EXPORT40 WITH MD5\n" +"E SSL2 DES 64 CBC WITH MD5\n" +"F SSL2 DES 192 EDE3 CBC WITH MD5\n" +"\n" +"a SSL3 FORTEZZA DMS WITH FORTEZZA CBC SHA\n" +"b SSL3 FORTEZZA DMS WITH RC4 128 SHA\n" +"c SSL3 RSA WITH RC4 128 MD5\n" +"d SSL3 RSA WITH 3DES EDE CBC SHA\n" +"e SSL3 RSA WITH DES CBC SHA\n" +"f SSL3 RSA EXPORT WITH RC4 40 MD5\n" +"g SSL3 RSA EXPORT WITH RC2 CBC 40 MD5\n" +"h SSL3 FORTEZZA DMS WITH NULL SHA\n" +"i SSL3 RSA WITH NULL MD5\n" +"j SSL3 RSA FIPS WITH 3DES EDE CBC SHA\n" +"k SSL3 RSA FIPS WITH DES CBC SHA\n" +"l SSL3 RSA EXPORT WITH DES CBC SHA\t(new)\n" +"m SSL3 RSA EXPORT WITH RC4 56 SHA\t(new)\n", + progName); + exit(1); +} + +/* Function: readDataFromSocket() + * + * Purpose: Parse an HTTP request by reading data from a GET or POST. + * + */ +SECStatus +readDataFromSocket(PRFileDesc *sslSocket, DataBuffer *buffer, char **fileName) +{ + char *post; + int numBytes = 0; + int newln = 0; /* # of consecutive newlns */ + + /* Read data while it comes in from the socket. */ + while (PR_TRUE) { + buffer->index = 0; + newln = 0; + + /* Read the buffer. */ + numBytes = PR_Read(sslSocket, &buffer->data[buffer->index], + buffer->remaining); + if (numBytes <= 0) { + errWarn("PR_Read"); + return SECFailure; + } + buffer->dataEnd = buffer->dataStart + numBytes; + + /* Parse the input, starting at the beginning of the buffer. + * Stop when we detect two consecutive \n's (or \r\n's) + * as this signifies the end of the GET or POST portion. + * The posted data follows. + */ + while (buffer->index < buffer->dataEnd && newln < 2) { + int octet = buffer->data[buffer->index++]; + if (octet == '\n') { + newln++; + } else if (octet != '\r') { + newln = 0; + } + } + + /* Came to the end of the buffer, or second newline. + * If we didn't get an empty line ("\r\n\r\n"), then keep on reading. + */ + if (newln < 2) + continue; + + /* we're at the end of the HTTP request. + * If the request is a POST, then there will be one more + * line of data. + * This parsing is a hack, but ok for SSL test purposes. + */ + post = PORT_Strstr(buffer->data, "POST "); + if (!post || *post != 'P') + break; + + /* It's a post, so look for the next and final CR/LF. */ + /* We should parse content length here, but ... */ + while (buffer->index < buffer->dataEnd && newln < 3) { + int octet = buffer->data[buffer->index++]; + if (octet == '\n') { + newln++; + } + } + + if (newln == 3) + break; + } + + /* Have either (a) a complete get, (b) a complete post, (c) EOF */ + + /* Execute a "GET " operation. */ + if (buffer->index > 0 && PORT_Strncmp(buffer->data, "GET ", 4) == 0) { + int fnLength; + + /* File name is the part after "GET ". */ + fnLength = strcspn(buffer->data + 5, " \r\n"); + *fileName = (char *)PORT_Alloc(fnLength + 1); + PORT_Strncpy(*fileName, buffer->data + 5, fnLength); + (*fileName)[fnLength] = '\0'; + } + + return SECSuccess; +} + +/* Function: authenticateSocket() + * + * Purpose: Configure a socket for SSL. + * + * + */ +PRFileDesc * +setupSSLSocket(PRFileDesc *tcpSocket, int requestCert) +{ + PRFileDesc *sslSocket; + SSLKEAType certKEA; + int certErr = 0; + SECStatus secStatus; + + /* Set the appropriate flags. */ + + sslSocket = SSL_ImportFD(NULL, tcpSocket); + if (sslSocket == NULL) { + errWarn("SSL_ImportFD"); + goto loser; + } + + secStatus = SSL_OptionSet(sslSocket, SSL_SECURITY, PR_TRUE); + if (secStatus != SECSuccess) { + errWarn("SSL_OptionSet SSL_SECURITY"); + goto loser; + } + + secStatus = SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_SERVER, PR_TRUE); + if (secStatus != SECSuccess) { + errWarn("SSL_OptionSet:SSL_HANDSHAKE_AS_SERVER"); + goto loser; + } + + secStatus = SSL_OptionSet(sslSocket, SSL_REQUEST_CERTIFICATE, + (requestCert >= REQUEST_CERT_ONCE)); + if (secStatus != SECSuccess) { + errWarn("SSL_OptionSet:SSL_REQUEST_CERTIFICATE"); + goto loser; + } + + secStatus = SSL_OptionSet(sslSocket, SSL_REQUIRE_CERTIFICATE, + (requestCert == REQUIRE_CERT_ONCE)); + if (secStatus != SECSuccess) { + errWarn("SSL_OptionSet:SSL_REQUIRE_CERTIFICATE"); + goto loser; + } + + /* Set the appropriate callback routines. */ + + secStatus = SSL_AuthCertificateHook(sslSocket, myAuthCertificate, + CERT_GetDefaultCertDB()); + if (secStatus != SECSuccess) { + errWarn("SSL_AuthCertificateHook"); + goto loser; + } + + secStatus = SSL_BadCertHook(sslSocket, + (SSLBadCertHandler)myBadCertHandler, &certErr); + if (secStatus != SECSuccess) { + errWarn("SSL_BadCertHook"); + goto loser; + } + + secStatus = SSL_HandshakeCallback(sslSocket, + (SSLHandshakeCallback)myHandshakeCallback, + NULL); + if (secStatus != SECSuccess) { + errWarn("SSL_HandshakeCallback"); + goto loser; + } + + secStatus = SSL_SetPKCS11PinArg(sslSocket, password); + if (secStatus != SECSuccess) { + errWarn("SSL_HandshakeCallback"); + goto loser; + } + + certKEA = NSS_FindCertKEAType(cert); + + secStatus = SSL_ConfigSecureServer(sslSocket, cert, privKey, certKEA); + if (secStatus != SECSuccess) { + errWarn("SSL_ConfigSecureServer"); + goto loser; + } + + return sslSocket; + +loser: + + PR_Close(tcpSocket); + return NULL; +} + +/* Function: authenticateSocket() + * + * Purpose: Perform client authentication on the socket. + * + */ +SECStatus +authenticateSocket(PRFileDesc *sslSocket, PRBool requireCert) +{ + CERTCertificate *cert; + SECStatus secStatus; + + /* Returns NULL if client authentication is not enabled or if the + * client had no certificate. */ + cert = SSL_PeerCertificate(sslSocket); + if (cert) { + /* Client had a certificate, so authentication is through. */ + CERT_DestroyCertificate(cert); + return SECSuccess; + } + + /* Request client to authenticate itself. */ + secStatus = SSL_OptionSet(sslSocket, SSL_REQUEST_CERTIFICATE, PR_TRUE); + if (secStatus != SECSuccess) { + errWarn("SSL_OptionSet:SSL_REQUEST_CERTIFICATE"); + return SECFailure; + } + + /* If desired, require client to authenticate itself. Note + * SSL_REQUEST_CERTIFICATE must also be on, as above. */ + secStatus = SSL_OptionSet(sslSocket, SSL_REQUIRE_CERTIFICATE, requireCert); + if (secStatus != SECSuccess) { + errWarn("SSL_OptionSet:SSL_REQUIRE_CERTIFICATE"); + return SECFailure; + } + + /* Having changed socket configuration parameters, redo handshake. */ + secStatus = SSL_ReHandshake(sslSocket, PR_TRUE); + if (secStatus != SECSuccess) { + errWarn("SSL_ReHandshake"); + return SECFailure; + } + + /* Force the handshake to complete before moving on. */ + secStatus = SSL_ForceHandshake(sslSocket); + if (secStatus != SECSuccess) { + errWarn("SSL_ForceHandshake"); + return SECFailure; + } + + return SECSuccess; +} + +/* Function: writeDataToSocket + * + * Purpose: Write the client's request back to the socket. If the client + * requested a file, dump it to the socket. + * + */ +SECStatus +writeDataToSocket(PRFileDesc *sslSocket, DataBuffer *buffer, char *fileName) +{ + int headerLength; + int numBytes; + char messageBuffer[120]; + PRFileDesc *local_file_fd = NULL; + char header[] = "<html><body><h1>Sample SSL server</h1><br><br>"; + char filehd[] = "<h2>The file you requested:</h2><br>"; + char reqhd[] = "<h2>This is your request:</h2><br>"; + char link[] = "Try getting a <a HREF=\"../testfile\">file</a><br>"; + char footer[] = "<br><h2>End of request.</h2><br></body></html>"; + + headerLength = PORT_Strlen(defaultHeader); + + /* Write a header to the socket. */ + numBytes = PR_Write(sslSocket, header, PORT_Strlen(header)); + if (numBytes < 0) { + errWarn("PR_Write"); + goto loser; + } + + if (fileName) { + PRFileInfo info; + PRStatus prStatus; + + /* Try to open the local file named. + * If successful, then write it to the client. + */ + prStatus = PR_GetFileInfo(fileName, &info); + if (prStatus != PR_SUCCESS || + info.type != PR_FILE_FILE || + info.size < 0) { + PORT_Free(fileName); + /* Maybe a GET not sent from client.c? */ + goto writerequest; + } + + local_file_fd = PR_Open(fileName, PR_RDONLY, 0); + if (local_file_fd == NULL) { + PORT_Free(fileName); + goto writerequest; + } + + /* Write a header to the socket. */ + numBytes = PR_Write(sslSocket, filehd, PORT_Strlen(filehd)); + if (numBytes < 0) { + errWarn("PR_Write"); + goto loser; + } + + /* Transmit the local file prepended by the default header + * across the socket. + */ + numBytes = PR_TransmitFile(sslSocket, local_file_fd, + defaultHeader, headerLength, + PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + + /* Error in transmission. */ + if (numBytes < 0) { + errWarn("PR_TransmitFile"); + /* + i = PORT_Strlen(errString); + PORT_Memcpy(buf, errString, i); + */ + /* Transmitted bytes successfully. */ + } else { + numBytes -= headerLength; + fprintf(stderr, "PR_TransmitFile wrote %d bytes from %s\n", + numBytes, fileName); + } + + PORT_Free(fileName); + PR_Close(local_file_fd); + } + +writerequest: + + /* Write a header to the socket. */ + numBytes = PR_Write(sslSocket, reqhd, PORT_Strlen(reqhd)); + if (numBytes < 0) { + errWarn("PR_Write"); + goto loser; + } + + /* Write the buffer data to the socket. */ + if (buffer->index <= 0) { + /* Reached the EOF. Report incomplete transaction to socket. */ + PORT_Sprintf(messageBuffer, + "GET or POST incomplete after %d bytes.\r\n", + buffer->dataEnd); + numBytes = PR_Write(sslSocket, messageBuffer, + PORT_Strlen(messageBuffer)); + if (numBytes < 0) { + errWarn("PR_Write"); + goto loser; + } + } else { + /* Display the buffer data. */ + fwrite(buffer->data, 1, buffer->index, stdout); + /* Write the buffer data to the socket. */ + numBytes = PR_Write(sslSocket, buffer->data, buffer->index); + if (numBytes < 0) { + errWarn("PR_Write"); + goto loser; + } + /* Display security information for the socket. */ + printSecurityInfo(sslSocket); + /* Write any discarded data out to the socket. */ + if (buffer->index < buffer->dataEnd) { + PORT_Sprintf(buffer->data, "Discarded %d characters.\r\n", + buffer->dataEnd - buffer->index); + numBytes = PR_Write(sslSocket, buffer->data, + PORT_Strlen(buffer->data)); + if (numBytes < 0) { + errWarn("PR_Write"); + goto loser; + } + } + } + + /* Write a footer to the socket. */ + numBytes = PR_Write(sslSocket, footer, PORT_Strlen(footer)); + if (numBytes < 0) { + errWarn("PR_Write"); + goto loser; + } + + /* Write a link to the socket. */ + numBytes = PR_Write(sslSocket, link, PORT_Strlen(link)); + if (numBytes < 0) { + errWarn("PR_Write"); + goto loser; + } + + /* Complete the HTTP transaction. */ + numBytes = PR_Write(sslSocket, "EOF\r\n\r\n\r\n", 9); + if (numBytes < 0) { + errWarn("PR_Write"); + goto loser; + } + + /* Do a nice shutdown if asked. */ + if (!strncmp(buffer->data, stopCmd, strlen(stopCmd))) { + stopping = 1; + } + return SECSuccess; + +loser: + + /* Do a nice shutdown if asked. */ + if (!strncmp(buffer->data, stopCmd, strlen(stopCmd))) { + stopping = 1; + } + return SECFailure; +} + +/* Function: int handle_connection() + * + * Purpose: Thread to handle a connection to a socket. + * + */ +SECStatus +handle_connection(void *tcp_sock, int requestCert) +{ + PRFileDesc * tcpSocket = (PRFileDesc *)tcp_sock; + PRFileDesc * sslSocket = NULL; + SECStatus secStatus = SECFailure; + PRStatus prStatus; + PRSocketOptionData socketOption; + DataBuffer buffer; + char * fileName = NULL; + + /* Initialize the data buffer. */ + memset(buffer.data, 0, BUFFER_SIZE); + buffer.remaining = BUFFER_SIZE; + buffer.index = 0; + buffer.dataStart = 0; + buffer.dataEnd = 0; + + /* Make sure the socket is blocking. */ + socketOption.option = PR_SockOpt_Nonblocking; + socketOption.value.non_blocking = PR_FALSE; + PR_SetSocketOption(tcpSocket, &socketOption); + + sslSocket = setupSSLSocket(tcpSocket, requestCert); + if (sslSocket == NULL) { + errWarn("setupSSLSocket"); + goto cleanup; + } + + secStatus = SSL_ResetHandshake(sslSocket, /* asServer */ PR_TRUE); + if (secStatus != SECSuccess) { + errWarn("SSL_ResetHandshake"); + goto cleanup; + } + + /* Read data from the socket, parse it for HTTP content. + * If the user is requesting/requiring authentication, authenticate + * the socket. Then write the result back to the socket. */ + fprintf(stdout, "\nReading data from socket...\n\n"); + secStatus = readDataFromSocket(sslSocket, &buffer, &fileName); + if (secStatus != SECSuccess) { + goto cleanup; + } + if (requestCert >= REQUEST_CERT_ALL) { + fprintf(stdout, "\nAuthentication requested.\n\n"); + secStatus = authenticateSocket(sslSocket, + (requestCert == REQUIRE_CERT_ALL)); + if (secStatus != SECSuccess) { + goto cleanup; + } + } + + fprintf(stdout, "\nWriting data to socket...\n\n"); + secStatus = writeDataToSocket(sslSocket, &buffer, fileName); + +cleanup: + + /* Close down the socket. */ + prStatus = PR_Close(tcpSocket); + if (prStatus != PR_SUCCESS) { + errWarn("PR_Close"); + } + + return secStatus; +} + +/* Function: int accept_connection() + * + * Purpose: Thread to accept a connection to the socket. + * + */ +SECStatus +accept_connection(void *listener, int requestCert) +{ + PRFileDesc *listenSocket = (PRFileDesc*)listener; + PRNetAddr addr; + PRStatus prStatus; + + /* XXX need an SSL socket here? */ + while (!stopping) { + PRFileDesc *tcpSocket; + SECStatus result; + + fprintf(stderr, "\n\n\nAbout to call accept.\n"); + + /* Accept a connection to the socket. */ + tcpSocket = PR_Accept(listenSocket, &addr, PR_INTERVAL_NO_TIMEOUT); + if (tcpSocket == NULL) { + errWarn("PR_Accept"); + break; + } + + /* Accepted the connection, now handle it. */ + result = launch_thread(&threadMGR, handle_connection, + tcpSocket, requestCert); + + if (result != SECSuccess) { + prStatus = PR_Close(tcpSocket); + if (prStatus != PR_SUCCESS) { + exitErr("PR_Close"); + } + break; + } + } + + fprintf(stderr, "Closing listen socket.\n"); + + prStatus = PR_Close(listenSocket); + if (prStatus != PR_SUCCESS) { + exitErr("PR_Close"); + } + return SECSuccess; +} + +/* Function: void server_main() + * + * Purpose: This is the server's main function. It configures a socket + * and listens to it. + * + */ +void +server_main( + unsigned short port, + int requestCert, + SECKEYPrivateKey * privKey, + CERTCertificate * cert, + PRBool disableSSL3) +{ + SECStatus secStatus; + PRStatus prStatus; + PRFileDesc * listenSocket; + PRNetAddr addr; + PRSocketOptionData socketOption; + + /* Create a new socket. */ + listenSocket = PR_NewTCPSocket(); + if (listenSocket == NULL) { + exitErr("PR_NewTCPSocket"); + } + + /* Set socket to be blocking - + * on some platforms the default is nonblocking. + */ + socketOption.option = PR_SockOpt_Nonblocking; + socketOption.value.non_blocking = PR_FALSE; + + prStatus = PR_SetSocketOption(listenSocket, &socketOption); + if (prStatus != PR_SUCCESS) { + exitErr("PR_SetSocketOption"); + } + + /* This cipher is not on by default. The Acceptance test + * would like it to be. Turn this cipher on. + */ + secStatus = SSL_CipherPrefSetDefault(SSL_RSA_WITH_NULL_MD5, PR_TRUE); + if (secStatus != SECSuccess) { + exitErr("SSL_CipherPrefSetDefault:SSL_RSA_WITH_NULL_MD5"); + } + + /* Configure the network connection. */ + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_INADDR_ANY; + addr.inet.port = PR_htons(port); + + /* Bind the address to the listener socket. */ + prStatus = PR_Bind(listenSocket, &addr); + if (prStatus != PR_SUCCESS) { + exitErr("PR_Bind"); + } + + /* Listen for connection on the socket. The second argument is + * the maximum size of the queue for pending connections. + */ + prStatus = PR_Listen(listenSocket, 5); + if (prStatus != PR_SUCCESS) { + exitErr("PR_Listen"); + } + + /* Launch thread to handle connections to the socket. */ + secStatus = launch_thread(&threadMGR, accept_connection, + listenSocket, requestCert); + if (secStatus != SECSuccess) { + PR_Close(listenSocket); + } else { + reap_threads(&threadMGR); + destroy_thread_data(&threadMGR); + } +} + +/* Function: int main() + * + * Purpose: Parses command arguments and configures SSL server. + * + */ +int +main(int argc, char **argv) +{ + char * progName = NULL; + char * nickName = NULL; + char * cipherString = NULL; + char * dir = "."; + int requestCert = 0; + unsigned short port = 0; + SECStatus secStatus; + PRBool disableSSL3 = PR_FALSE; + PLOptState * optstate; + PLOptStatus status; + + /* Zero out the thread manager. */ + PORT_Memset(&threadMGR, 0, sizeof(threadMGR)); + + progName = PL_strdup(argv[0]); + + optstate = PL_CreateOptState(argc, argv, "3FRc:d:fp:n:rw:"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch(optstate->option) { + case '3': disableSSL3 = PR_TRUE; break; + case 'F': requestCert = REQUIRE_CERT_ALL; break; + case 'R': requestCert = REQUEST_CERT_ALL; break; + case 'c': cipherString = PL_strdup(optstate->value); break; + case 'd': dir = PL_strdup(optstate->value); break; + case 'f': requestCert = REQUIRE_CERT_ONCE; break; + case 'n': nickName = PL_strdup(optstate->value); break; + case 'p': port = PORT_Atoi(optstate->value); break; + case 'r': requestCert = REQUEST_CERT_ONCE; break; + case 'w': password = PL_strdup(optstate->value); break; + default: + case '?': Usage(progName); + } + } + + if (nickName == NULL || port == 0) + Usage(progName); + + /* Call the NSPR initialization routines. */ + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + + /* Set the cert database password callback. */ + PK11_SetPasswordFunc(myPasswd); + + /* Initialize NSS. */ + secStatus = NSS_Init(dir); + if (secStatus != SECSuccess) { + exitErr("NSS_Init"); + } + + /* Set the policy for this server (REQUIRED - no default). */ + secStatus = NSS_SetDomesticPolicy(); + if (secStatus != SECSuccess) { + exitErr("NSS_SetDomesticPolicy"); + } + + /* XXX keep this? */ + /* all the SSL2 and SSL3 cipher suites are enabled by default. */ + if (cipherString) { + int ndx; + + /* disable all the ciphers, then enable the ones we want. */ + disableAllSSLCiphers(); + + while (0 != (ndx = *cipherString++)) { + int *cptr; + int cipher; + + if (! isalpha(ndx)) + Usage(progName); + cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites; + for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; ) + /* do nothing */; + if (cipher) { + SECStatus status; + status = SSL_CipherPrefSetDefault(cipher, PR_TRUE); + if (status != SECSuccess) + errWarn("SSL_CipherPrefSetDefault()"); + } + } + } + + /* Get own certificate and private key. */ + cert = PK11_FindCertFromNickname(nickName, password); + if (cert == NULL) { + exitErr("PK11_FindCertFromNickname"); + } + + privKey = PK11_FindKeyByAnyCert(cert, password); + if (privKey == NULL) { + exitErr("PK11_FindKeyByAnyCert"); + } + + /* Configure the server's cache for a multi-process application + * using default timeout values (24 hrs) and directory location (/tmp). + */ + SSL_ConfigMPServerSIDCache(256, 0, 0, NULL); + + /* Launch server. */ + server_main(port, requestCert, privKey, cert, disableSSL3); + + /* Shutdown NSS and exit NSPR gracefully. */ + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + PR_Cleanup(); + return 0; +} diff --git a/security/nss/cmd/SSLsample/server.mn b/security/nss/cmd/SSLsample/server.mn new file mode 100644 index 000000000..3ce1181d9 --- /dev/null +++ b/security/nss/cmd/SSLsample/server.mn @@ -0,0 +1,48 @@ +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +MODULE = nss + +EXPORTS = + +CSRCS = server.c \ + sslsample.c \ + $(NULL) + +PROGRAM = server + +REQUIRES = dbm + +DEFINES = -DNSPR20 + diff --git a/security/nss/cmd/SSLsample/sslerror.h b/security/nss/cmd/SSLsample/sslerror.h new file mode 100644 index 000000000..8ad908569 --- /dev/null +++ b/security/nss/cmd/SSLsample/sslerror.h @@ -0,0 +1,110 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "nspr.h" + +struct tuple_str { + PRErrorCode errNum; + const char * errString; +}; + +typedef struct tuple_str tuple_str; + +#define ER2(a,b) {a, b}, +#define ER3(a,b,c) {a, c}, + +#include "secerr.h" +#include "sslerr.h" + +const tuple_str errStrings[] = { + +/* keep this list in asceding order of error numbers */ +#include "SSLerrs.h" +#include "SECerrs.h" +#include "NSPRerrs.h" + +}; + +const PRInt32 numStrings = sizeof(errStrings) / sizeof(tuple_str); + +/* Returns a UTF-8 encoded constant error string for "errNum". + * Returns NULL of errNum is unknown. + */ +const char * +SSL_Strerror(PRErrorCode errNum) { + PRInt32 low = 0; + PRInt32 high = numStrings - 1; + PRInt32 i; + PRErrorCode num; + static int initDone; + + /* make sure table is in ascending order. + * binary search depends on it. + */ + if (!initDone) { + PRErrorCode lastNum = (PRInt32)0x80000000; + for (i = low; i <= high; ++i) { + num = errStrings[i].errNum; + if (num <= lastNum) { + fprintf(stderr, +"sequence error in error strings at item %d\n" +"error %d (%s)\n" +"should come after \n" +"error %d (%s)\n", + i, lastNum, errStrings[i-1].errString, + num, errStrings[i].errString); + } + lastNum = num; + } + initDone = 1; + } + + /* Do binary search of table. */ + while (low + 1 < high) { + i = (low + high) / 2; + num = errStrings[i].errNum; + if (errNum == num) + return errStrings[i].errString; + if (errNum < num) + high = i; + else + low = i; + } + if (errNum == errStrings[low].errNum) + return errStrings[low].errString; + if (errNum == errStrings[high].errNum) + return errStrings[high].errString; + return NULL; +} diff --git a/security/nss/cmd/SSLsample/sslsample.c b/security/nss/cmd/SSLsample/sslsample.c new file mode 100644 index 000000000..5a25b940d --- /dev/null +++ b/security/nss/cmd/SSLsample/sslsample.c @@ -0,0 +1,591 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "sslsample.h" +#include "sslerror.h" + +/* Declare SSL cipher suites. */ + +int ssl2CipherSuites[] = { + SSL_EN_RC4_128_WITH_MD5, /* A */ + SSL_EN_RC4_128_EXPORT40_WITH_MD5, /* B */ + SSL_EN_RC2_128_CBC_WITH_MD5, /* C */ + SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */ + SSL_EN_DES_64_CBC_WITH_MD5, /* E */ + SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* F */ + 0 +}; + +int ssl3CipherSuites[] = { + SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, /* a */ + SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, /* b */ + SSL_RSA_WITH_RC4_128_MD5, /* c */ + SSL_RSA_WITH_3DES_EDE_CBC_SHA, /* d */ + SSL_RSA_WITH_DES_CBC_SHA, /* e */ + SSL_RSA_EXPORT_WITH_RC4_40_MD5, /* f */ + SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* g */ + SSL_FORTEZZA_DMS_WITH_NULL_SHA, /* h */ + SSL_RSA_WITH_NULL_MD5, /* i */ + SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, /* j */ + SSL_RSA_FIPS_WITH_DES_CBC_SHA, /* k */ + TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, /* l */ + TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, /* m */ + 0 +}; + +/************************************************************************** +** +** SSL callback routines. +** +**************************************************************************/ + +/* Function: char * myPasswd() + * + * Purpose: This function is our custom password handler that is called by + * SSL when retreiving private certs and keys from the database. Returns a + * pointer to a string that with a password for the database. Password pointer + * should point to dynamically allocated memory that will be freed later. + */ +char * +myPasswd(PK11SlotInfo *info, PRBool retry, void *arg) +{ + char * passwd = NULL; + + if ( (!retry) && arg ) { + passwd = PORT_Strdup((char *)arg); + } + + return passwd; +} + +/* Function: SECStatus myAuthCertificate() + * + * Purpose: This function is our custom certificate authentication handler. + * + * Note: This implementation is essentially the same as the default + * SSL_AuthCertificate(). + */ +SECStatus +myAuthCertificate(void *arg, PRFileDesc *socket, + PRBool checksig, PRBool isServer) +{ + + SECCertUsage certUsage; + CERTCertificate * cert; + void * pinArg; + char * hostName; + SECStatus secStatus; + + if (!arg || !socket) { + errWarn("myAuthCertificate"); + return SECFailure; + } + + /* Define how the cert is being used based upon the isServer flag. */ + + certUsage = isServer ? certUsageSSLClient : certUsageSSLServer; + + cert = SSL_PeerCertificate(socket); + + pinArg = SSL_RevealPinArg(socket); + + secStatus = CERT_VerifyCertNow((CERTCertDBHandle *)arg, + cert, + checksig, + certUsage, + pinArg); + + /* If this is a server, we're finished. */ + if (isServer || secStatus != SECSuccess) { + CERT_DestroyCertificate(cert); + return secStatus; + } + + /* Certificate is OK. Since this is the client side of an SSL + * connection, we need to verify that the name field in the cert + * matches the desired hostname. This is our defense against + * man-in-the-middle attacks. + */ + + /* SSL_RevealURL returns a hostName, not an URL. */ + hostName = SSL_RevealURL(socket); + + if (hostName && hostName[0]) { + secStatus = CERT_VerifyCertName(cert, hostName); + } else { + PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0); + secStatus = SECFailure; + } + + if (hostName) + PR_Free(hostName); + + CERT_DestroyCertificate(cert); + return secStatus; +} + +/* Function: SECStatus myBadCertHandler() + * + * Purpose: This callback is called when the incoming certificate is not + * valid. We define a certain set of parameters that still cause the + * certificate to be "valid" for this session, and return SECSuccess to cause + * the server to continue processing the request when any of these conditions + * are met. Otherwise, SECFailure is return and the server rejects the + * request. + */ +SECStatus +myBadCertHandler(void *arg, PRFileDesc *socket) +{ + + SECStatus secStatus = SECFailure; + PRErrorCode err; + + /* log invalid cert here */ + + if (!arg) { + return secStatus; + } + + *(PRErrorCode *)arg = err = PORT_GetError(); + + /* If any of the cases in the switch are met, then we will proceed */ + /* with the processing of the request anyway. Otherwise, the default */ + /* case will be reached and we will reject the request. */ + + switch (err) { + case SEC_ERROR_INVALID_AVA: + case SEC_ERROR_INVALID_TIME: + case SEC_ERROR_BAD_SIGNATURE: + case SEC_ERROR_EXPIRED_CERTIFICATE: + case SEC_ERROR_UNKNOWN_ISSUER: + case SEC_ERROR_UNTRUSTED_CERT: + case SEC_ERROR_CERT_VALID: + case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: + case SEC_ERROR_CRL_EXPIRED: + case SEC_ERROR_CRL_BAD_SIGNATURE: + case SEC_ERROR_EXTENSION_VALUE_INVALID: + case SEC_ERROR_CA_CERT_INVALID: + case SEC_ERROR_CERT_USAGES_INVALID: + case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION: + secStatus = SECSuccess; + break; + default: + secStatus = SECFailure; + break; + } + + printf("Bad certificate: %d, %s\n", err, SSL_Strerror(err)); + + return secStatus; +} + +/* Function: SECStatus ownGetClientAuthData() + * + * Purpose: This callback is used by SSL to pull client certificate + * information upon server request. + */ +SECStatus +myGetClientAuthData(void *arg, + PRFileDesc *socket, + struct CERTDistNamesStr *caNames, + struct CERTCertificateStr **pRetCert, + struct SECKEYPrivateKeyStr **pRetKey) +{ + + CERTCertificate * cert; + SECKEYPrivateKey * privKey; + char * chosenNickName = (char *)arg; + void * proto_win = NULL; + SECStatus secStatus = SECFailure; + + proto_win = SSL_RevealPinArg(socket); + + if (chosenNickName) { + cert = PK11_FindCertFromNickname(chosenNickName, proto_win); + if (cert) { + privKey = PK11_FindKeyByAnyCert(cert, proto_win); + if (privKey) { + secStatus = SECSuccess; + } else { + CERT_DestroyCertificate(cert); + } + } + } else { /* no nickname given, automatically find the right cert */ + CERTCertNicknames *names; + int i; + + names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(), + SEC_CERT_NICKNAMES_USER, proto_win); + + if (names != NULL) { + for(i = 0; i < names->numnicknames; i++ ) { + + cert = PK11_FindCertFromNickname(names->nicknames[i], + proto_win); + if (!cert) { + continue; + } + + /* Only check unexpired certs */ + if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE) + != secCertTimeValid ) { + CERT_DestroyCertificate(cert); + continue; + } + + secStatus = NSS_CmpCertChainWCANames(cert, caNames); + if (secStatus == SECSuccess) { + privKey = PK11_FindKeyByAnyCert(cert, proto_win); + if (privKey) { + break; + } + secStatus = SECFailure; + break; + } + CERT_FreeNicknames(names); + } /* for loop */ + } + } + + if (secStatus == SECSuccess) { + *pRetCert = cert; + *pRetKey = privKey; + } + + return secStatus; +} + +/* Function: SECStatus myHandshakeCallback() + * + * Purpose: Called by SSL to inform application that the handshake is + * complete. This function is mostly used on the server side of an SSL + * connection, although it is provided for a client as well. + * Useful when a non-blocking SSL_ReHandshake or SSL_ResetHandshake + * is used to initiate a handshake. + * + * A typical scenario would be: + * + * 1. Server accepts an SSL connection from the client without client auth. + * 2. Client sends a request. + * 3. Server determines that to service request it needs to authenticate the + * client and initiates another handshake requesting client auth. + * 4. While handshake is in progress, server can do other work or spin waiting + * for the handshake to complete. + * 5. Server is notified that handshake has been successfully completed by + * the custom handshake callback function and it can service the client's + * request. + * + * Note: This function is not implemented in this sample, as we are using + * blocking sockets. + */ +SECStatus +myHandshakeCallback(PRFileDesc *socket, void *arg) +{ + printf("Handshake has completed, ready to send data securely.\n"); + return SECSuccess; +} + + +/************************************************************************** +** +** Routines for disabling SSL ciphers. +** +**************************************************************************/ + +void +disableAllSSLCiphers(void) +{ + const PRUint16 *cipherSuites = SSL_ImplementedCiphers; + int i = SSL_NumImplementedCiphers; + SECStatus rv; + + /* disable all the SSL3 cipher suites */ + while (--i >= 0) { + PRUint16 suite = cipherSuites[i]; + rv = SSL_CipherPrefSetDefault(suite, PR_FALSE); + if (rv != SECSuccess) { + printf("SSL_CipherPrefSetDefault didn't like value 0x%04x (i = %d)\n", + suite, i); + errWarn("SSL_CipherPrefSetDefault"); + exit(2); + } + } +} + +/************************************************************************** +** +** Error and information routines. +** +**************************************************************************/ + +void +errWarn(char *function) +{ + PRErrorCode errorNumber = PR_GetError(); + const char * errorString = SSL_Strerror(errorNumber); + + printf("Error in function %s: %d\n - %s\n", + function, errorNumber, errorString); +} + +void +exitErr(char *function) +{ + errWarn(function); + /* Exit gracefully. */ + /* ignoring return value of NSS_Shutdown as code exits with 1*/ + (void) NSS_Shutdown(); + PR_Cleanup(); + exit(1); +} + +void +printSecurityInfo(PRFileDesc *fd) +{ + char * cp; /* bulk cipher name */ + char * ip; /* cert issuer DN */ + char * sp; /* cert subject DN */ + int op; /* High, Low, Off */ + int kp0; /* total key bits */ + int kp1; /* secret key bits */ + int result; + SSL3Statistics * ssl3stats = SSL_GetStatistics(); + + result = SSL_SecurityStatus(fd, &op, &cp, &kp0, &kp1, &ip, &sp); + if (result != SECSuccess) + return; + printf("bulk cipher %s, %d secret key bits, %d key bits, status: %d\n" + "subject DN: %s\n" + "issuer DN: %s\n", cp, kp1, kp0, op, sp, ip); + PR_Free(cp); + PR_Free(ip); + PR_Free(sp); + + printf("%ld cache hits; %ld cache misses, %ld cache not reusable\n", + ssl3stats->hch_sid_cache_hits, ssl3stats->hch_sid_cache_misses, + ssl3stats->hch_sid_cache_not_ok); + +} + + +/************************************************************************** +** Begin thread management routines and data. +**************************************************************************/ + +void +thread_wrapper(void * arg) +{ + GlobalThreadMgr *threadMGR = (GlobalThreadMgr *)arg; + perThread *slot = &threadMGR->threads[threadMGR->index]; + + /* wait for parent to finish launching us before proceeding. */ + PR_Lock(threadMGR->threadLock); + PR_Unlock(threadMGR->threadLock); + + slot->rv = (* slot->startFunc)(slot->a, slot->b); + + PR_Lock(threadMGR->threadLock); + slot->running = rs_zombie; + + /* notify the thread exit handler. */ + PR_NotifyCondVar(threadMGR->threadEndQ); + + PR_Unlock(threadMGR->threadLock); +} + +SECStatus +launch_thread(GlobalThreadMgr *threadMGR, + startFn *startFunc, + void *a, + int b) +{ + perThread *slot; + int i; + + if (!threadMGR->threadStartQ) { + threadMGR->threadLock = PR_NewLock(); + threadMGR->threadStartQ = PR_NewCondVar(threadMGR->threadLock); + threadMGR->threadEndQ = PR_NewCondVar(threadMGR->threadLock); + } + PR_Lock(threadMGR->threadLock); + while (threadMGR->numRunning >= MAX_THREADS) { + PR_WaitCondVar(threadMGR->threadStartQ, PR_INTERVAL_NO_TIMEOUT); + } + for (i = 0; i < threadMGR->numUsed; ++i) { + slot = &threadMGR->threads[i]; + if (slot->running == rs_idle) + break; + } + if (i >= threadMGR->numUsed) { + if (i >= MAX_THREADS) { + /* something's really wrong here. */ + PORT_Assert(i < MAX_THREADS); + PR_Unlock(threadMGR->threadLock); + return SECFailure; + } + ++(threadMGR->numUsed); + PORT_Assert(threadMGR->numUsed == i + 1); + slot = &threadMGR->threads[i]; + } + + slot->a = a; + slot->b = b; + slot->startFunc = startFunc; + + threadMGR->index = i; + + slot->prThread = PR_CreateThread(PR_USER_THREAD, + thread_wrapper, threadMGR, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, 0); + + if (slot->prThread == NULL) { + PR_Unlock(threadMGR->threadLock); + printf("Failed to launch thread!\n"); + return SECFailure; + } + + slot->inUse = 1; + slot->running = 1; + ++(threadMGR->numRunning); + PR_Unlock(threadMGR->threadLock); + printf("Launched thread in slot %d \n", threadMGR->index); + + return SECSuccess; +} + +SECStatus +reap_threads(GlobalThreadMgr *threadMGR) +{ + perThread * slot; + int i; + + if (!threadMGR->threadLock) + return 0; + PR_Lock(threadMGR->threadLock); + while (threadMGR->numRunning > 0) { + PR_WaitCondVar(threadMGR->threadEndQ, PR_INTERVAL_NO_TIMEOUT); + for (i = 0; i < threadMGR->numUsed; ++i) { + slot = &threadMGR->threads[i]; + if (slot->running == rs_zombie) { + /* Handle cleanup of thread here. */ + printf("Thread in slot %d returned %d\n", i, slot->rv); + + /* Now make sure the thread has ended OK. */ + PR_JoinThread(slot->prThread); + slot->running = rs_idle; + --threadMGR->numRunning; + + /* notify the thread launcher. */ + PR_NotifyCondVar(threadMGR->threadStartQ); + } + } + } + + /* Safety Sam sez: make sure count is right. */ + for (i = 0; i < threadMGR->numUsed; ++i) { + slot = &threadMGR->threads[i]; + if (slot->running != rs_idle) { + fprintf(stderr, "Thread in slot %d is in state %d!\n", + i, slot->running); + } + } + PR_Unlock(threadMGR->threadLock); + return 0; +} + +void +destroy_thread_data(GlobalThreadMgr *threadMGR) +{ + PORT_Memset(threadMGR->threads, 0, sizeof(threadMGR->threads)); + + if (threadMGR->threadEndQ) { + PR_DestroyCondVar(threadMGR->threadEndQ); + threadMGR->threadEndQ = NULL; + } + if (threadMGR->threadStartQ) { + PR_DestroyCondVar(threadMGR->threadStartQ); + threadMGR->threadStartQ = NULL; + } + if (threadMGR->threadLock) { + PR_DestroyLock(threadMGR->threadLock); + threadMGR->threadLock = NULL; + } +} + +/************************************************************************** +** End thread management routines. +**************************************************************************/ + +void +lockedVars_Init( lockedVars * lv) +{ + lv->count = 0; + lv->waiters = 0; + lv->lock = PR_NewLock(); + lv->condVar = PR_NewCondVar(lv->lock); +} + +void +lockedVars_Destroy( lockedVars * lv) +{ + PR_DestroyCondVar(lv->condVar); + lv->condVar = NULL; + + PR_DestroyLock(lv->lock); + lv->lock = NULL; +} + +void +lockedVars_WaitForDone(lockedVars * lv) +{ + PR_Lock(lv->lock); + while (lv->count > 0) { + PR_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(lv->lock); +} + +int /* returns count */ +lockedVars_AddToCount(lockedVars * lv, int addend) +{ + int rv; + + PR_Lock(lv->lock); + rv = lv->count += addend; + if (rv <= 0) { + PR_NotifyCondVar(lv->condVar); + } + PR_Unlock(lv->lock); + return rv; +} diff --git a/security/nss/cmd/SSLsample/sslsample.h b/security/nss/cmd/SSLsample/sslsample.h new file mode 100644 index 000000000..ca6b6a489 --- /dev/null +++ b/security/nss/cmd/SSLsample/sslsample.h @@ -0,0 +1,178 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 SSLSAMPLE_H +#define SSLSAMPLE_H + +/* Generic header files */ + +#include <stdio.h> +#include <string.h> + +/* NSPR header files */ + +#include "nspr.h" +#include "prerror.h" +#include "prnetdb.h" + +/* NSS header files */ + +#include "pk11func.h" +#include "secitem.h" +#include "ssl.h" +#include "certt.h" +#include "nss.h" +#include "secrng.h" +#include "secder.h" +#include "key.h" +#include "sslproto.h" + +/* Custom header files */ + +/* +#include "sslerror.h" +*/ + +#define BUFFER_SIZE 10240 + +/* Declare SSL cipher suites. */ + +extern int cipherSuites[]; +extern int ssl2CipherSuites[]; +extern int ssl3CipherSuites[]; + +/* Data buffer read from a socket. */ +typedef struct DataBufferStr { + char data[BUFFER_SIZE]; + int index; + int remaining; + int dataStart; + int dataEnd; +} DataBuffer; + +/* SSL callback routines. */ + +char * myPasswd(PK11SlotInfo *info, PRBool retry, void *arg); + +SECStatus myAuthCertificate(void *arg, PRFileDesc *socket, + PRBool checksig, PRBool isServer); + +SECStatus myBadCertHandler(void *arg, PRFileDesc *socket); + +SECStatus myHandshakeCallback(PRFileDesc *socket, void *arg); + +SECStatus myGetClientAuthData(void *arg, PRFileDesc *socket, + struct CERTDistNamesStr *caNames, + struct CERTCertificateStr **pRetCert, + struct SECKEYPrivateKeyStr **pRetKey); + +/* Disable all v2/v3 SSL ciphers. */ + +void disableAllSSLCiphers(void); + + +/* Error and information utilities. */ + +void errWarn(char *function); + +void exitErr(char *function); + +void printSecurityInfo(PRFileDesc *fd); + +/* Some simple thread management routines. */ + +#define MAX_THREADS 32 + +typedef SECStatus startFn(void *a, int b); + +typedef enum { rs_idle = 0, rs_running = 1, rs_zombie = 2 } runState; + +typedef struct perThreadStr { + PRFileDesc *a; + int b; + int rv; + startFn *startFunc; + PRThread *prThread; + PRBool inUse; + runState running; +} perThread; + +typedef struct GlobalThreadMgrStr { + PRLock *threadLock; + PRCondVar *threadStartQ; + PRCondVar *threadEndQ; + perThread threads[MAX_THREADS]; + int index; + int numUsed; + int numRunning; +} GlobalThreadMgr; + +void thread_wrapper(void * arg); + +SECStatus launch_thread(GlobalThreadMgr *threadMGR, + startFn *startFunc, void *a, int b); + +SECStatus reap_threads(GlobalThreadMgr *threadMGR); + +void destroy_thread_data(GlobalThreadMgr *threadMGR); + +/* Management of locked variables. */ + +struct lockedVarsStr { + PRLock * lock; + int count; + int waiters; + PRCondVar * condVar; +}; + +typedef struct lockedVarsStr lockedVars; + +void lockedVars_Init(lockedVars *lv); + +void lockedVars_Destroy(lockedVars *lv); + +void lockedVars_WaitForDone(lockedVars *lv); + +int lockedVars_AddToCount(lockedVars *lv, int addend); + +/* Buffer stuff. */ + +static const char stopCmd[] = { "GET /stop " }; +static const char defaultHeader[] = { + "HTTP/1.0 200 OK\r\n" + "Server: SSL sample server\r\n" + "Content-type: text/plain\r\n" + "\r\n" +}; + +#endif diff --git a/security/nss/cmd/addbuiltin/Makefile b/security/nss/cmd/addbuiltin/Makefile new file mode 100644 index 000000000..8650a607d --- /dev/null +++ b/security/nss/cmd/addbuiltin/Makefile @@ -0,0 +1,76 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/addbuiltin/addbuiltin.c b/security/nss/cmd/addbuiltin/addbuiltin.c new file mode 100644 index 000000000..86161c94a --- /dev/null +++ b/security/nss/cmd/addbuiltin/addbuiltin.c @@ -0,0 +1,357 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* + * Tool for converting builtin CA certs. + * + * $Id$ + */ + +#include "nss.h" +#include "cert.h" +#include "certdb.h" +#include "secutil.h" +#include "pk11func.h" + +void dumpbytes(unsigned char *buf, int len) +{ + int i; + for (i=0; i < len; i++) { + if ((i !=0) && ((i & 0xf) == 0)) { + printf("\n"); + } + printf("\\%03o",buf[i]); + } + printf("\n"); +} + +char *getTrustString(unsigned int trust) +{ + if (trust & CERTDB_TRUSTED) { + if (trust & CERTDB_TRUSTED_CA) { + return "CKT_NETSCAPE_TRUSTED_DELEGATOR|CKT_NETSCAPE_TRUSTED"; + } else { + return "CKT_NETSCAPE_TRUSTED"; + } + } else { + if (trust & CERTDB_TRUSTED_CA) { + return "CKT_NETSCAPE_TRUSTED_DELEGATOR"; + } else { + return "CKT_NETSCAPE_VALID"; + } + } + return "CKT_NETSCAPE_VALID"; /* not reached */ +} + +static const SEC_ASN1Template serialTemplate[] = { + { SEC_ASN1_INTEGER, offsetof(CERTCertificate,serialNumber) }, + { 0 } +}; + +static SECStatus +ConvertCertificate(SECItem *sdder, char *nickname, CERTCertTrust *trust) +{ + SECStatus rv = SECSuccess; + CERTCertificate *cert; + unsigned char sha1_hash[SHA1_LENGTH]; + unsigned char md5_hash[MD5_LENGTH]; + SECItem *serial = NULL; + + cert = CERT_DecodeDERCertificate(sdder, PR_FALSE, nickname); + if (!cert) { + return SECFailure; + } + serial = SEC_ASN1EncodeItem(NULL,NULL,cert,serialTemplate); + if (!serial) { + return SECFailure; + } + + printf("\n#\n# Certificate \"%s\"\n#\n",nickname); + printf("CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE\n"); + printf("CKA_TOKEN CK_BBOOL CK_TRUE\n"); + printf("CKA_PRIVATE CK_BBOOL CK_FALSE\n"); + printf("CKA_MODIFIABLE CK_BBOOL CK_FALSE\n"); + printf("CKA_LABEL UTF8 \"%s\"\n",nickname); + printf("CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509\n"); + printf("CKA_SUBJECT MULTILINE_OCTAL\n"); + dumpbytes(cert->derSubject.data,cert->derSubject.len); + printf("END\n"); + printf("CKA_ID UTF8 \"0\"\n"); + printf("CKA_ISSUER MULTILINE_OCTAL\n"); + dumpbytes(cert->derIssuer.data,cert->derIssuer.len); + printf("END\n"); + printf("CKA_SERIAL_NUMBER MULTILINE_OCTAL\n"); + dumpbytes(serial->data,serial->len); + printf("END\n"); + printf("CKA_VALUE MULTILINE_OCTAL\n"); + dumpbytes(sdder->data,sdder->len); + printf("END\n"); + + PK11_HashBuf(SEC_OID_SHA1, sha1_hash, sdder->data, sdder->len); + PK11_HashBuf(SEC_OID_MD5, md5_hash, sdder->data, sdder->len); + printf("\n# Trust for Certificate \"%s\"\n",nickname); + printf("CKA_CLASS CK_OBJECT_CLASS CKO_NETSCAPE_TRUST\n"); + printf("CKA_TOKEN CK_BBOOL CK_TRUE\n"); + printf("CKA_PRIVATE CK_BBOOL CK_FALSE\n"); + printf("CKA_MODIFIABLE CK_BBOOL CK_FALSE\n"); + printf("CKA_LABEL UTF8 \"%s\"\n",nickname); + printf("CKA_CERT_SHA1_HASH MULTILINE_OCTAL\n"); + dumpbytes(sha1_hash,SHA1_LENGTH); + printf("END\n"); + printf("CKA_CERT_MD5_HASH MULTILINE_OCTAL\n"); + dumpbytes(md5_hash,MD5_LENGTH); + printf("END\n"); + + printf("CKA_ISSUER MULTILINE_OCTAL\n"); + dumpbytes(cert->derIssuer.data,cert->derIssuer.len); + printf("END\n"); + printf("CKA_SERIAL_NUMBER MULTILINE_OCTAL\n"); + dumpbytes(serial->data,serial->len); + printf("END\n"); + + printf("CKA_TRUST_SERVER_AUTH CK_TRUST %s\n", + getTrustString(trust->sslFlags)); + printf("CKA_TRUST_EMAIL_PROTECTION CK_TRUST %s\n", + getTrustString(trust->emailFlags)); + printf("CKA_TRUST_CODE_SIGNING CK_TRUST %s\n", + getTrustString(trust->objectSigningFlags)); +#ifdef notdef + printf("CKA_TRUST_CLIENT_AUTH CK_TRUST CKT_NETSCAPE_TRUSTED\n");*/ + printf("CKA_TRUST_DIGITAL_SIGNATURE CK_TRUST CKT_NETSCAPE_TRUSTED_DELEGATOR\n"); + printf("CKA_TRUST_NON_REPUDIATION CK_TRUST CKT_NETSCAPE_TRUSTED_DELEGATOR\n"); + printf("CKA_TRUST_KEY_ENCIPHERMENT CK_TRUST CKT_NETSCAPE_TRUSTED_DELEGATOR\n"); + printf("CKA_TRUST_DATA_ENCIPHERMENT CK_TRUST CKT_NETSCAPE_TRUSTED_DELEGATOR\n"); + printf("CKA_TRUST_KEY_AGREEMENT CK_TRUST CKT_NETSCAPE_TRUSTED_DELEGATOR\n"); + printf("CKA_TRUST_KEY_CERT_SIGN CK_TRUST CKT_NETSCAPE_TRUSTED_DELEGATOR\n"); +#endif + + + PORT_Free(sdder->data); + return(rv); + +} + +printheader() { + printf("# \n" + "# The contents of this file are subject to the Mozilla Public\n" + "# License Version 1.1 (the \"License\"); you may not use this file\n" + "# except in compliance with the License. You may obtain a copy of\n" + "# the License at http://www.mozilla.org/MPL/\n" + "# \n" + "# Software distributed under the License is distributed on an \"AS\n" + "# IS\" basis, WITHOUT WARRANTY OF ANY KIND, either express or\n" + "# implied. See the License for the specific language governing\n" + "# rights and limitations under the License.\n" + "# \n" + "# The Original Code is the Netscape security libraries.\n" + "# \n" + "# The Initial Developer of the Original Code is Netscape\n" + "# Communications Corporation. Portions created by Netscape are \n" + "# Copyright (C) 1994-2000 Netscape Communications Corporation. All\n" + "# Rights Reserved.\n" + "# \n" + "# Contributor(s):\n" + "# \n" + "# Alternatively, the contents of this file may be used under the\n" + "# terms of the GNU General Public License Version 2 or later (the\n" + "# \"GPL\"), in which case the provisions of the GPL are applicable \n" + "# instead of those above. If you wish to allow use of your \n" + "# version of this file only under the terms of the GPL and not to\n" + "# allow others to use your version of this file under the MPL,\n" + "# indicate your decision by deleting the provisions above and\n" + "# replace them with the notice and other provisions required by\n" + "# the GPL. If you do not delete the provisions above, a recipient\n" + "# may use your version of this file under either the MPL or the\n" + "# GPL.\n" + "#\n" + "CVS_ID \"@(#) $RCSfile$ $Revision$ $Date$ $Name$\"\n" + "\n" + "#\n" + "# certdata.txt\n" + "#\n" + "# This file contains the object definitions for the certs and other\n" + "# information \"built into\" NSS.\n" + "#\n" + "# Object definitions:\n" + "#\n" + "# Certificates\n" + "#\n" + "# -- Attribute -- -- type -- -- value --\n" + "# CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE\n" + "# CKA_TOKEN CK_BBOOL CK_TRUE\n" + "# CKA_PRIVATE CK_BBOOL CK_FALSE\n" + "# CKA_MODIFIABLE CK_BBOOL CK_FALSE\n" + "# CKA_LABEL UTF8 (varies)\n" + "# CKA_CERTIFICATE_TYPE CK_CERTIFICATE_TYPE CKC_X_509\n" + "# CKA_SUBJECT DER+base64 (varies)\n" + "# CKA_ID byte array (varies)\n" + "# CKA_ISSUER DER+base64 (varies)\n" + "# CKA_SERIAL_NUMBER DER+base64 (varies)\n" + "# CKA_VALUE DER+base64 (varies)\n" + "# CKA_NETSCAPE_EMAIL ASCII7 (unused here)\n" + "#\n" + "# Trust\n" + "#\n" + "# -- Attribute -- -- type -- -- value --\n" + "# CKA_CLASS CK_OBJECT_CLASS CKO_TRUST\n" + "# CKA_TOKEN CK_BBOOL CK_TRUE\n" + "# CKA_PRIVATE CK_BBOOL CK_FALSE\n" + "# CKA_MODIFIABLE CK_BBOOL CK_FALSE\n" + "# CKA_LABEL UTF8 (varies)\n" + "# CKA_ISSUER DER+base64 (varies)\n" + "# CKA_SERIAL_NUMBER DER+base64 (varies)\n" + "# CKA_CERT_HASH binary+base64 (varies)\n" + "# CKA_EXPIRES CK_DATE (not used here)\n" + "# CKA_TRUST_DIGITAL_SIGNATURE CK_TRUST (varies)\n" + "# CKA_TRUST_NON_REPUDIATION CK_TRUST (varies)\n" + "# CKA_TRUST_KEY_ENCIPHERMENT CK_TRUST (varies)\n" + "# CKA_TRUST_DATA_ENCIPHERMENT CK_TRUST (varies)\n" + "# CKA_TRUST_KEY_AGREEMENT CK_TRUST (varies)\n" + "# CKA_TRUST_KEY_CERT_SIGN CK_TRUST (varies)\n" + "# CKA_TRUST_CRL_SIGN CK_TRUST (varies)\n" + "# CKA_TRUST_SERVER_AUTH CK_TRUST (varies)\n" + "# CKA_TRUST_CLIENT_AUTH CK_TRUST (varies)\n" + "# CKA_TRUST_CODE_SIGNING CK_TRUST (varies)\n" + "# CKA_TRUST_EMAIL_PROTECTION CK_TRUST (varies)\n" + "# CKA_TRUST_IPSEC_END_SYSTEM CK_TRUST (varies)\n" + "# CKA_TRUST_IPSEC_TUNNEL CK_TRUST (varies)\n" + "# CKA_TRUST_IPSEC_USER CK_TRUST (varies)\n" + "# CKA_TRUST_TIME_STAMPING CK_TRUST (varies)\n" + "# (other trust attributes can be defined)\n" + "#\n" + "\n" + "#\n" + "# The object to tell NSS that this is a root list and we don't\n" + "# have to go looking for others.\n" + "#\n" + "BEGINDATA\n" + "CKA_CLASS CK_OBJECT_CLASS CKO_NETSCAPE_BUILTIN_ROOT_LIST\n" + "CKA_TOKEN CK_BBOOL CK_TRUE\n" + "CKA_PRIVATE CK_BBOOL CK_FALSE\n" + "CKA_MODIFIABLE CK_BBOOL CK_FALSE\n" + "CKA_LABEL UTF8 \"Mozilla Builtin Roots\"\n"); +} + +static void Usage(char *progName) +{ + fprintf(stderr, "%s -n nickname -t trust\n", progName); + fprintf(stderr, + "read a der-encoded cert from stdin in, and output\n" + "it to stdout in a format suitable for the builtin root module.\n" + "example: %s -n MyCA -t \"C,C,C\" < myca.der >> certdata.txt\n" + "(pipe through atob if the cert is b64-encoded)\n"); + fprintf(stderr, "%15s nickname to assign to builtin cert.\n", + "-n nickname"); + fprintf(stderr, "%15s default trust flags (cCTpPuw).\n", + "-t trust"); + exit(-1); +} + +enum { + opt_Input = 0, + opt_Nickname, + opt_Trust +}; + +static secuCommandFlag addbuiltin_options[] = +{ + { /* opt_Input */ 'i', PR_TRUE, 0, PR_FALSE }, + { /* opt_Nickname */ 'n', PR_TRUE, 0, PR_FALSE }, + { /* opt_Trust */ 't', PR_TRUE, 0, PR_FALSE } +}; + +main(int argc, char **argv) +{ + SECStatus rv; + char *nickname; + char *trusts; + char *progName; + PRFileDesc *infile; + CERTCertTrust trust = { 0 }; + SECItem derCert = { 0 }; + + secuCommand addbuiltin = { 0 }; + addbuiltin.numOptions = sizeof(addbuiltin_options)/sizeof(secuCommandFlag); + addbuiltin.options = addbuiltin_options; + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + rv = SECU_ParseCommandLine(argc, argv, progName, &addbuiltin); + + if (rv != SECSuccess) + Usage(progName); + + if (!addbuiltin.options[opt_Nickname].activated && + !addbuiltin.options[opt_Trust].activated) { + fprintf(stderr, "%s: you must specify both a nickname and trust.\n"); + Usage(progName); + } + + if (addbuiltin.options[opt_Input].activated) { + infile = PR_Open(addbuiltin.options[opt_Input].arg, PR_RDONLY, 00660); + if (!infile) { + fprintf(stderr, "%s: failed to open input file.\n"); + exit(1); + } + } else { + infile = PR_STDIN; + } + + nickname = strdup(addbuiltin.options[opt_Nickname].arg); + trusts = strdup(addbuiltin.options[opt_Trust].arg); + + NSS_NoDB_Init(NULL); + + rv = CERT_DecodeTrustString(&trust, trusts); + if (rv) { + fprintf(stderr, "%s: incorrectly formatted trust string.\n", progName); + Usage(progName); + } + + SECU_FileToItem(&derCert, infile); + + /*printheader();*/ + + rv = ConvertCertificate(&derCert, nickname, &trust); + if (rv) { + fprintf(stderr, "%s: failed to convert certificate.\n", progName); + exit(1); + } + + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + + return(SECSuccess); +} diff --git a/security/nss/cmd/addbuiltin/manifest.mn b/security/nss/cmd/addbuiltin/manifest.mn new file mode 100644 index 000000000..b800ed92a --- /dev/null +++ b/security/nss/cmd/addbuiltin/manifest.mn @@ -0,0 +1,49 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +CSRCS = \ + addbuiltin.c \ + $(NULL) + +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = dbm seccmd + +PROGRAM = addbuiltin + +USE_STATIC_LIBS = 1 diff --git a/security/nss/cmd/atob/Makefile b/security/nss/cmd/atob/Makefile new file mode 100644 index 000000000..ff6f06e7e --- /dev/null +++ b/security/nss/cmd/atob/Makefile @@ -0,0 +1,76 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/atob/atob.c b/security/nss/cmd/atob/atob.c new file mode 100644 index 000000000..8d632b6bf --- /dev/null +++ b/security/nss/cmd/atob/atob.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 "plgetopt.h" +#include "secutil.h" +#include "nssb64.h" +#include <errno.h> + +#if defined(XP_WIN) || (defined(__sun) && !defined(SVR4)) +#if !defined(WIN32) +extern int fread(char *, size_t, size_t, FILE*); +extern int fwrite(char *, size_t, size_t, FILE*); +extern int fprintf(FILE *, char *, ...); +#endif +#endif + +#if defined(WIN32) +#include "fcntl.h" +#include "io.h" +#endif + +static PRInt32 +output_binary (void *arg, const unsigned char *obuf, PRInt32 size) +{ + FILE *outFile = arg; + int nb; + + nb = fwrite(obuf, 1, size, outFile); + if (nb != size) { + PORT_SetError(SEC_ERROR_IO); + return -1; + } + + return nb; +} + +static SECStatus +decode_file(FILE *outFile, FILE *inFile) +{ + NSSBase64Decoder *cx; + int nb; + SECStatus status = SECFailure; + char ibuf[4096]; + + cx = NSSBase64Decoder_Create(output_binary, outFile); + if (!cx) { + return -1; + } + + for (;;) { + if (feof(inFile)) break; + nb = fread(ibuf, 1, sizeof(ibuf), inFile); + if (nb != sizeof(ibuf)) { + if (nb == 0) { + if (ferror(inFile)) { + PORT_SetError(SEC_ERROR_IO); + goto loser; + } + /* eof */ + break; + } + } + + status = NSSBase64Decoder_Update(cx, ibuf, nb); + if (status != SECSuccess) goto loser; + } + + return NSSBase64Decoder_Destroy(cx, PR_FALSE); + + loser: + (void) NSSBase64Decoder_Destroy(cx, PR_TRUE); + return status; +} + +static void Usage(char *progName) +{ + fprintf(stderr, + "Usage: %s [-i input] [-o output]\n", + progName); + fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n", + "-i input"); + fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n", + "-o output"); + exit(-1); +} + +int main(int argc, char **argv) +{ + char *progName; + SECStatus rv; + FILE *inFile, *outFile; + PLOptState *optstate; + PLOptStatus status; + + inFile = 0; + outFile = 0; + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + /* Parse command line arguments */ + optstate = PL_CreateOptState(argc, argv, "i:o:"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case '?': + Usage(progName); + break; + + case 'i': + inFile = fopen(optstate->value, "r"); + if (!inFile) { + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", + progName, optstate->value); + return -1; + } + break; + + case 'o': + outFile = fopen(optstate->value, "wb"); + if (!outFile) { + fprintf(stderr, "%s: unable to open \"%s\" for writing\n", + progName, optstate->value); + return -1; + } + break; + } + } + if (!inFile) inFile = stdin; + if (!outFile) { +#if defined(WIN32) + int smrv = _setmode(_fileno(stdout), _O_BINARY); + if (smrv == -1) { + fprintf(stderr, + "%s: Cannot change stdout to binary mode. Use -o option instead.\n", + progName); + return smrv; + } +#endif + outFile = stdout; + } + rv = decode_file(outFile, inFile); + if (rv != SECSuccess) { + fprintf(stderr, "%s: lossage: error=%d errno=%d\n", + progName, PORT_GetError(), errno); + return -1; + } + return 0; +} diff --git a/security/nss/cmd/atob/makefile.win b/security/nss/cmd/atob/makefile.win new file mode 100644 index 000000000..ecccc7bf3 --- /dev/null +++ b/security/nss/cmd/atob/makefile.win @@ -0,0 +1,155 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +VERBOSE = 1 +include <manifest.mn> + +#cannot define PROGRAM in manifest compatibly with NT and UNIX +PROGRAM = atob +PROGRAM = ./$(OBJDIR)/$(PROGRAM).exe +include <$(DEPTH)\config\config.mak> + +# let manifest generate C_OBJS, it will prepend ./$(OBJDIR)/ +# rules.mak will append C_OBJS onto OBJS. +# OBJS = $(CSRCS:.c=.obj) + +# include files are looked for in $LINCS and $INCS. +# $LINCS is in manifest.mnw, computed from REQUIRES= +INCS = $(INCS) \ + -I$(DEPTH)/security/lib/cert \ + -I../include \ + $(NULL) + +IGNORE_ME = \ + -I$(DEPTH)/security/lib/key \ + -I$(DEPTH)/security/lib/util \ + $(NULL) + + +WINFE = $(DEPTH)/cmd/winfe/mkfiles$(MOZ_BITS)/x86Dbg + +# these files are the content of libdbm +DBM_LIB = \ + $(WINFE)/DB.obj \ + $(WINFE)/HASH.obj \ + $(WINFE)/H_BIGKEY.obj \ + $(WINFE)/H_PAGE.obj \ + $(WINFE)/H_LOG2.obj \ + $(WINFE)/H_FUNC.obj \ + $(WINFE)/HASH_BUF.obj \ + $(NULL) + +MOZ_LIBS = \ + $(WINFE)/ALLXPSTR.obj \ + $(WINFE)/XP_ERROR.obj \ + $(WINFE)/XPASSERT.obj \ + $(WINFE)/XP_REG.obj \ + $(WINFE)/XP_TRACE.obj \ + $(DBM_LIB) \ + $(WINFE)/XP_STR.obj \ + $(WINFE)/MKTEMP.obj \ + $(NULL) + +SEC_LIBS = \ + $(DIST)/lib/cert$(MOZ_BITS).lib \ + $(DIST)/lib/crypto$(MOZ_BITS).lib \ + $(DIST)/lib/hash$(MOZ_BITS).lib \ + $(DIST)/lib/key$(MOZ_BITS).lib \ + $(DIST)/lib/pkcs7$(MOZ_BITS).lib \ + $(DIST)/lib/secmod$(MOZ_BITS).lib \ + $(DIST)/lib/secutl$(MOZ_BITS).lib \ + $(DIST)/lib/ssl$(MOZ_BITS).lib \ + $(NULL) + +LLFLAGS = $(LLFLAGS) \ + ../lib/$(OBJDIR)/sectool$(MOZ_BITS).lib \ + $(SEC_LIBS) \ + $(MOZ_LIBS) \ + $(DEPTH)/nspr/src/$(OBJDIR)/getopt.obj \ + $(LIBNSPR) \ + $(NULL) + + +# awt3240.lib # brpref32.lib # cert32.lib +# crypto32.lib # dllcom.lib # editor32.lib +# edpref32.lib # edtplug.lib # font.lib +# hash32.lib # htmldg32.lib # img32.lib +# javart32.lib # jbn3240.lib # jdb3240.lib +# jmc.lib # jpeg3240.lib # jpw3240.lib +# jrt3240.lib # js3240.lib # jsd3240.lib +# key32.lib # libapplet32.lib # libnjs32.lib +# libnsc32.lib # libreg32.lib # mm3240.lib +# mnpref32.lib # netcst32.lib # nsdlg32.lib +# nsldap32.lib # nsldaps32.lib # nsn32.lib +# pkcs1232.lib # pkcs732.lib # pr3240.lib +# prefui32.lib # prefuuid.lib # secmod32.lib +# secnav32.lib # secutl32.lib # softup32.lib +# sp3240.lib # ssl32.lib # uni3200.lib +# unicvt32.lib # win32md.lib # winfont.lib +# xppref32.lib # zlib32.lib + +include <$(DEPTH)\config\rules.mak> + +INSTALL = $(MAKE_INSTALL) + +objs: $(OBJS) + +$(PROGRAM):: + $(INSTALL) $(DIST)/bin/pr3240.dll ./$(OBJDIR) + +programs: $(PROGRAM) + +install:: $(TARGETS) + $(INSTALL) $(TARGETS) $(DIST)/bin + +# ALLXPSTR.obj XP_ALLOC.obj XP_HASH.obj XP_RGB.obj XP_WRAP.obj +# CXPRINT.obj XP_C.cl XP_LIST.obj XP_SEC.obj netscape.exp +# CXPRNDLG.obj XP_CNTXT.obj XP_MD5.obj XP_STR.obj xp.pch +# EXPORT.obj XP_CORE.obj XP_MESG.obj XP_THRMO.obj xppref32.dll +# XPASSERT.obj XP_ERROR.obj XP_RECT.obj XP_TIME.obj +# XPLOCALE.obj XP_FILE.obj XP_REG.obj XP_TRACE.obj + + +symbols: + @echo "CSRCS = $(CSRCS)" + @echo "INCS = $(INCS)" + @echo "OBJS = $(OBJS)" + @echo "LIBRARY = $(LIBRARY)" + @echo "PROGRAM = $(PROGRAM)" + @echo "TARGETS = $(TARGETS)" + @echo "DIST = $(DIST)" + @echo "VERSION_NUMBER = $(VERSION_NUMBER)" + @echo "WINFE = $(WINFE)" + @echo "DBM_LIB = $(DBM_LIB)" + @echo "INSTALL = $(INSTALL)" + diff --git a/security/nss/cmd/atob/manifest.mn b/security/nss/cmd/atob/manifest.mn new file mode 100644 index 000000000..f6c20bf19 --- /dev/null +++ b/security/nss/cmd/atob/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +# This next line is used by .mk files +# and gets translated into $LINCS in manifest.mnw +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = seccmd dbm + +DEFINES = -DNSPR20 + +CSRCS = atob.c + +PROGRAM = atob + diff --git a/security/nss/cmd/bltest/Makefile b/security/nss/cmd/bltest/Makefile new file mode 100644 index 000000000..c99a3c017 --- /dev/null +++ b/security/nss/cmd/bltest/Makefile @@ -0,0 +1,82 @@ +#! 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 +#MKPROG = purify -cache-dir=/u/mcgreer/pcache -best-effort \ +# -always-use-cache-dir $(CC) + +####################################################################### +# (2) Include "global" configuration information. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +#EXTRA_SHARED_LIBS += \ +# -L/usr/lib \ +# -lposix4 \ +# $(NULL) + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +include ../platrules.mk diff --git a/security/nss/cmd/bltest/blapitest.c b/security/nss/cmd/bltest/blapitest.c new file mode 100644 index 000000000..b3000b257 --- /dev/null +++ b/security/nss/cmd/bltest/blapitest.c @@ -0,0 +1,2572 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 <stdlib.h> + +#include "blapi.h" +#include "secrng.h" +#include "prmem.h" +#include "prprf.h" +#include "prtime.h" +#include "prsystem.h" +#include "plstr.h" +#include "nssb64.h" +#include "secutil.h" +#include "plgetopt.h" +#include "softoken.h" +#include "nss.h" + +/* Temporary - add debugging ouput on windows for RSA to track QA failure */ +#ifdef _WIN32 +#define TRACK_BLTEST_BUG + char __bltDBG[] = "BLTEST DEBUG"; +#endif + +char *progName; +char *testdir = NULL; + +#define BLTEST_DEFAULT_CHUNKSIZE 4096 + +#define WORDSIZE sizeof(unsigned long) + +#define CHECKERROR(rv, ln) \ + if (rv) { \ + PRErrorCode prerror = PR_GetError(); \ + PR_fprintf(PR_STDERR, "%s: ERR %d (%s) at line %d.\n", progName, \ + prerror, SECU_Strerror(prerror), ln); \ + exit(-1); \ + } + +/* Macros for performance timing. */ +#define TIMESTART() \ + time1 = PR_IntervalNow(); + +#define TIMEFINISH(time, reps) \ + time2 = (PRIntervalTime)(PR_IntervalNow() - time1); \ + time1 = PR_IntervalToMilliseconds(time2); \ + time = ((double)(time1))/reps; + +static void Usage() +{ +#define PRINTUSAGE(subject, option, predicate) \ + fprintf(stderr, "%10s %s\t%s\n", subject, option, predicate); + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "[-DEHSV]", "List available cipher modes"); /* XXX */ + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "-E -m mode ", "Encrypt a buffer"); + PRINTUSAGE("", "", "[-i plaintext] [-o ciphertext] [-k key] [-v iv]"); + PRINTUSAGE("", "", "[-b bufsize] [-g keysize] [-e exp] [-r rounds]"); + PRINTUSAGE("", "", "[-w wordsize] [-p repetitions]"); + PRINTUSAGE("", "-m", "cipher mode to use"); + PRINTUSAGE("", "-i", "file which contains input buffer"); + PRINTUSAGE("", "-o", "file for output buffer"); + PRINTUSAGE("", "-k", "file which contains key"); + PRINTUSAGE("", "-v", "file which contains initialization vector"); + PRINTUSAGE("", "-b", "size of input buffer"); + PRINTUSAGE("", "-g", "key size (in bytes)"); + PRINTUSAGE("", "-p", "do performance test"); + PRINTUSAGE("(rsa)", "-e", "rsa public exponent"); + PRINTUSAGE("(rc5)", "-r", "number of rounds"); + PRINTUSAGE("(rc5)", "-w", "wordsize (32 or 64)"); + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "-D -m mode", "Decrypt a buffer"); + PRINTUSAGE("", "", "[-i plaintext] [-o ciphertext] [-k key] [-v iv]"); + PRINTUSAGE("", "", "[-p repetitions]"); + PRINTUSAGE("", "-m", "cipher mode to use"); + PRINTUSAGE("", "-i", "file which contains input buffer"); + PRINTUSAGE("", "-o", "file for output buffer"); + PRINTUSAGE("", "-k", "file which contains key"); + PRINTUSAGE("", "-v", "file which contains initialization vector"); + PRINTUSAGE("", "-p", "do performance test"); + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "-H -m mode", "Hash a buffer"); + PRINTUSAGE("", "", "[-i plaintext] [-o hash]"); + PRINTUSAGE("", "", "[-b bufsize]"); + PRINTUSAGE("", "", "[-p repetitions]"); + PRINTUSAGE("", "-m", "cipher mode to use"); + PRINTUSAGE("", "-i", "file which contains input buffer"); + PRINTUSAGE("", "-o", "file for hash"); + PRINTUSAGE("", "-b", "size of input buffer"); + PRINTUSAGE("", "-p", "do performance test"); + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "-S -m mode", "Sign a buffer"); + PRINTUSAGE("", "", "[-i plaintext] [-o signature] [-k key]"); + PRINTUSAGE("", "", "[-b bufsize]"); + PRINTUSAGE("", "", "[-p repetitions]"); + PRINTUSAGE("", "-m", "cipher mode to use"); + PRINTUSAGE("", "-i", "file which contains input buffer"); + PRINTUSAGE("", "-o", "file for signature"); + PRINTUSAGE("", "-k", "file which contains key"); + PRINTUSAGE("", "-p", "do performance test"); + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "-V -m mode", "Verify a signed buffer"); + PRINTUSAGE("", "", "[-i plaintext] [-s signature] [-k key]"); + PRINTUSAGE("", "", "[-p repetitions]"); + PRINTUSAGE("", "-m", "cipher mode to use"); + PRINTUSAGE("", "-i", "file which contains input buffer"); + PRINTUSAGE("", "-s", "file which contains signature of input buffer"); + PRINTUSAGE("", "-k", "file which contains key"); + PRINTUSAGE("", "-p", "do performance test"); + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "-N -m mode -b bufsize", + "Create a nonce plaintext and key"); + PRINTUSAGE("", "", "[-g keysize] [-u cxreps]"); + PRINTUSAGE("", "-g", "key size (in bytes)"); + PRINTUSAGE("", "-u", "number of repetitions of context creation"); + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "-F", "Run the FIPS self-test"); + fprintf(stderr, "\n"); + PRINTUSAGE(progName, "-T [-m mode1,mode2...]", "Run the BLAPI self-test"); + fprintf(stderr, "\n"); + exit(1); +} + +/* Helper functions for ascii<-->binary conversion/reading/writing */ + +/* XXX argh */ +struct item_with_arena { + SECItem *item; + PRArenaPool *arena; +}; + +static PRInt32 +get_binary(void *arg, const unsigned char *ibuf, PRInt32 size) +{ + struct item_with_arena *it = arg; + SECItem *binary = it->item; + SECItem *tmp; + int index; + if (binary->data == NULL) { + tmp = SECITEM_AllocItem(it->arena, NULL, size); + binary->data = tmp->data; + binary->len = tmp->len; + index = 0; + } else { + SECITEM_ReallocItem(NULL, binary, binary->len, binary->len + size); + index = binary->len; + } + PORT_Memcpy(&binary->data[index], ibuf, size); + return binary->len; +} + +static SECStatus +atob(SECItem *ascii, SECItem *binary, PRArenaPool *arena) +{ + SECStatus status; + NSSBase64Decoder *cx; + struct item_with_arena it; + int len; + binary->data = NULL; + binary->len = 0; + it.item = binary; + it.arena = arena; + len = (strcmp(&ascii->data[ascii->len-2],"\r\n")) ? + ascii->len : ascii->len-2; + cx = NSSBase64Decoder_Create(get_binary, &it); + status = NSSBase64Decoder_Update(cx, (const char *)ascii->data, len); + status = NSSBase64Decoder_Destroy(cx, PR_FALSE); + return status; +} + +static PRInt32 +output_ascii(void *arg, const char *obuf, PRInt32 size) +{ + PRFileDesc *outfile = arg; + PRInt32 nb = PR_Write(outfile, obuf, size); + if (nb != size) { + PORT_SetError(SEC_ERROR_IO); + return -1; + } + return nb; +} + +static SECStatus +btoa_file(SECItem *binary, PRFileDesc *outfile) +{ + SECStatus status; + NSSBase64Encoder *cx; + SECItem ascii; + ascii.data = NULL; + ascii.len = 0; + if (binary->len == 0) + return SECSuccess; + cx = NSSBase64Encoder_Create(output_ascii, outfile); + status = NSSBase64Encoder_Update(cx, binary->data, binary->len); + status = NSSBase64Encoder_Destroy(cx, PR_FALSE); + status = PR_Write(outfile, "\r\n", 2); + return status; +} + +SECStatus +hex_from_2char(unsigned char *c2, unsigned char *byteval) +{ + int i; + unsigned char offset; + *byteval = 0; + for (i=0; i<2; i++) { + if (c2[i] >= '0' && c2[i] <= '9') { + offset = c2[i] - '0'; + *byteval |= offset << 4*(1-i); + } else if (c2[i] >= 'a' && c2[i] <= 'f') { + offset = c2[i] - 'a'; + *byteval |= (offset + 10) << 4*(1-i); + } else if (c2[i] >= 'A' && c2[i] <= 'F') { + offset = c2[i] - 'A'; + *byteval |= (offset + 10) << 4*(1-i); + } else { + return SECFailure; + } + } + return SECSuccess; +} + +SECStatus +char2_from_hex(unsigned char byteval, unsigned char *c2) +{ + int i; + unsigned char offset; + for (i=0; i<2; i++) { + offset = (byteval >> 4*(1-i)) & 0x0f; + if (offset < 10) { + c2[i] = '0' + offset; + } else { + c2[i] = 'A' + offset - 10; + } + } + return SECSuccess; +} + +void +serialize_key(SECItem *it, int ni, PRFileDesc *file) +{ + unsigned char len[4]; + int i; + SECStatus status; + NSSBase64Encoder *cx; + SECItem ascii; + ascii.data = NULL; + ascii.len = 0; + cx = NSSBase64Encoder_Create(output_ascii, file); + for (i=0; i<ni; i++, it++) { + len[0] = (it->len >> 24) & 0xff; + len[1] = (it->len >> 16) & 0xff; + len[2] = (it->len >> 8) & 0xff; + len[3] = (it->len & 0xff); + status = NSSBase64Encoder_Update(cx, len, 4); + status = NSSBase64Encoder_Update(cx, it->data, it->len); + } + status = NSSBase64Encoder_Destroy(cx, PR_FALSE); + status = PR_Write(file, "\r\n", 2); +} + +void +key_from_filedata(PRArenaPool *arena, SECItem *it, int ni, SECItem *filedata) +{ + int fpos = 0; + int i; + unsigned char *buf = filedata->data; + for (i=0; i<ni; i++, it++) { + it->len = (buf[fpos++] & 0xff) << 24; + it->len |= (buf[fpos++] & 0xff) << 16; + it->len |= (buf[fpos++] & 0xff) << 8; + it->len |= (buf[fpos++] & 0xff); + if (it->len > 0) { + it->data = PORT_ArenaAlloc(arena, it->len); + PORT_Memcpy(it->data, &buf[fpos], it->len); + } else { + it->data = NULL; + } + fpos += it->len; + } +} + +static RSAPrivateKey * +rsakey_from_filedata(SECItem *filedata) +{ + RSAPrivateKey *key; + PRArenaPool *arena; + arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE); + key = (RSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(RSAPrivateKey)); + key->arena = arena; + key_from_filedata(arena, &key->version, 9, filedata); + return key; +} + +static PQGParams * +pqg_from_filedata(SECItem *filedata) +{ + PQGParams *pqg; + PRArenaPool *arena; + arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE); + pqg = (PQGParams *)PORT_ArenaZAlloc(arena, sizeof(PQGParams)); + pqg->arena = arena; + key_from_filedata(arena, &pqg->prime, 3, filedata); + return pqg; +} + +static DSAPrivateKey * +dsakey_from_filedata(SECItem *filedata) +{ + DSAPrivateKey *key; + PRArenaPool *arena; + arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE); + key = (DSAPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(DSAPrivateKey)); + key->params.arena = arena; + key_from_filedata(arena, &key->params.prime, 5, filedata); + return key; +} + +static void +dump_pqg(PQGParams *pqg) +{ + SECU_PrintInteger(stdout, &pqg->prime, "PRIME:", 0); + SECU_PrintInteger(stdout, &pqg->subPrime, "SUBPRIME:", 0); + SECU_PrintInteger(stdout, &pqg->base, "BASE:", 0); +} + +static void +dump_dsakey(DSAPrivateKey *key) +{ + dump_pqg(&key->params); + SECU_PrintInteger(stdout, &key->publicValue, "PUBLIC VALUE:", 0); + SECU_PrintInteger(stdout, &key->privateValue, "PRIVATE VALUE:", 0); +} + +static void +dump_rsakey(RSAPrivateKey *key) +{ + SECU_PrintInteger(stdout, &key->version, "VERSION:", 0); + SECU_PrintInteger(stdout, &key->modulus, "MODULUS:", 0); + SECU_PrintInteger(stdout, &key->publicExponent, "PUBLIC EXP:", 0); + SECU_PrintInteger(stdout, &key->privateExponent, "PRIVATE EXP:", 0); + SECU_PrintInteger(stdout, &key->prime1, "CRT PRIME 1:", 0); + SECU_PrintInteger(stdout, &key->prime2, "CRT PRIME 2:", 0); + SECU_PrintInteger(stdout, &key->exponent1, "CRT EXP 1:", 0); + SECU_PrintInteger(stdout, &key->exponent2, "CRT EXP 2:", 0); + SECU_PrintInteger(stdout, &key->coefficient, "CRT COEFFICIENT:", 0); +} + +typedef enum { + bltestBase64Encoded, /* Base64 encoded ASCII */ + bltestBinary, /* straight binary */ + bltestHexSpaceDelim, /* 0x12 0x34 0xab 0xCD ... */ + bltestHexStream /* 1234abCD ... */ +} bltestIOMode; + +typedef struct +{ + SECItem buf; + SECItem pBuf; + bltestIOMode mode; + PRFileDesc* file; +} bltestIO; + +typedef SECStatus (* bltestSymmCipherFn)(void *cx, + unsigned char *output, + unsigned int *outputLen, + unsigned int maxOutputLen, + const unsigned char *input, + unsigned int inputLen); + +typedef SECStatus (* bltestPubKeyCipherFn)(void *key, + SECItem *output, + const SECItem *input); + +typedef SECStatus (* bltestHashCipherFn)(unsigned char *dest, + const unsigned char *src, + uint32 src_length); + +typedef enum { + bltestINVALID = -1, + bltestDES_ECB, /* Symmetric Key Ciphers */ + bltestDES_CBC, /* . */ + bltestDES_EDE_ECB, /* . */ + bltestDES_EDE_CBC, /* . */ + bltestRC2_ECB, /* . */ + bltestRC2_CBC, /* . */ + bltestRC4, /* . */ + bltestRC5_ECB, /* . */ + bltestRC5_CBC, /* . */ + bltestAES_ECB, /* . */ + bltestAES_CBC, /* . */ + bltestRSA, /* Public Key Ciphers */ + bltestDSA, /* . (Public Key Sig.) */ + bltestMD2, /* Hash algorithms */ + bltestMD5, /* . */ + bltestSHA1, /* . */ + bltestSHA256, /* . */ + bltestSHA384, /* . */ + bltestSHA512, /* . */ + NUMMODES +} bltestCipherMode; + +static char *mode_strings[] = +{ + "des_ecb", + "des_cbc", + "des3_ecb", + "des3_cbc", + "rc2_ecb", + "rc2_cbc", + "rc4", + "rc5_ecb", + "rc5_cbc", + "aes_ecb", + "aes_cbc", + "rsa", + /*"pqg",*/ + "dsa", + "md2", + "md5", + "sha1", + "sha256", + "sha384", + "sha512", +}; + +typedef struct +{ + bltestIO key; + bltestIO iv; +} bltestSymmKeyParams; + +typedef struct +{ + bltestIO key; + bltestIO iv; + int rounds; + int wordsize; +} bltestRC5Params; + +typedef struct +{ + bltestIO key; + int keysizeInBits; + RSAPrivateKey *rsakey; +} bltestRSAParams; + +typedef struct +{ + bltestIO key; + bltestIO pqgdata; + unsigned int j; + bltestIO keyseed; + bltestIO sigseed; + bltestIO sig; /* if doing verify, have additional input */ + PQGParams *pqg; + DSAPrivateKey *dsakey; +} bltestDSAParams; + +typedef struct +{ + bltestIO key; /* unused */ + PRBool restart; +} bltestHashParams; + +typedef union +{ + bltestIO key; + bltestSymmKeyParams sk; + bltestRC5Params rc5; + bltestRSAParams rsa; + bltestDSAParams dsa; + bltestHashParams hash; +} bltestParams; + +typedef struct +{ + PRArenaPool *arena; + /* cipher context */ + void *cx; + /* I/O streams */ + bltestIO input; + bltestIO output; + /* Cipher-specific parameters */ + bltestParams params; + /* Cipher mode */ + bltestCipherMode mode; + /* Cipher function (encrypt/decrypt/sign/verify/hash) */ + union { + bltestSymmCipherFn symmkeyCipher; + bltestPubKeyCipherFn pubkeyCipher; + bltestHashCipherFn hashCipher; + } cipher; + /* performance testing */ + int repetitions; + int cxreps; + double cxtime; + double optime; +} bltestCipherInfo; + +PRBool +is_symmkeyCipher(bltestCipherMode mode) +{ + /* change as needed! */ + if (mode >= bltestDES_ECB && mode <= bltestAES_CBC) + return PR_TRUE; + return PR_FALSE; +} + +PRBool +is_pubkeyCipher(bltestCipherMode mode) +{ + /* change as needed! */ + if (mode >= bltestRSA && mode <= bltestDSA) + return PR_TRUE; + return PR_FALSE; +} + +PRBool +is_hashCipher(bltestCipherMode mode) +{ + /* change as needed! */ + if (mode >= bltestMD2 && mode <= bltestSHA512) + return PR_TRUE; + return PR_FALSE; +} + +PRBool +is_sigCipher(bltestCipherMode mode) +{ + /* change as needed! */ + if (mode >= bltestDSA && mode <= bltestDSA) + return PR_TRUE; + return PR_FALSE; +} + +PRBool +cipher_requires_IV(bltestCipherMode mode) +{ + /* change as needed! */ + if (mode == bltestDES_CBC || mode == bltestDES_EDE_CBC || + mode == bltestRC2_CBC || mode == bltestRC5_CBC || + mode == bltestAES_CBC) + return PR_TRUE; + return PR_FALSE; +} + +SECStatus finishIO(bltestIO *output, PRFileDesc *file); + +SECStatus +setupIO(PRArenaPool *arena, bltestIO *input, PRFileDesc *file, + char *str, int numBytes) +{ + SECStatus rv = SECSuccess; + SECItem fileData; + SECItem *in; + unsigned char *tok; + unsigned int i, j; + + if (file && (numBytes == 0 || file == PR_STDIN)) { + /* grabbing data from a file */ + rv = SECU_FileToItem(&fileData, file); + if (rv != SECSuccess) { + PR_Close(file); + return SECFailure; + } + in = &fileData; + } else if (str) { + /* grabbing data from command line */ + fileData.data = str; + fileData.len = PL_strlen(str); + in = &fileData; + } else if (file) { + /* create nonce */ + SECITEM_AllocItem(arena, &input->buf, numBytes); + RNG_GenerateGlobalRandomBytes(input->buf.data, numBytes); + return finishIO(input, file); + } else { + return SECFailure; + } + + switch (input->mode) { + case bltestBase64Encoded: + rv = atob(in, &input->buf, arena); + break; + case bltestBinary: + if (in->data[in->len-1] == '\n') --in->len; + if (in->data[in->len-1] == '\r') --in->len; + SECITEM_CopyItem(arena, &input->buf, in); + break; + case bltestHexSpaceDelim: + SECITEM_AllocItem(arena, &input->buf, in->len/5); + for (i=0, j=0; i<in->len; i+=5, j++) { + tok = &in->data[i]; + if (tok[0] != '0' || tok[1] != 'x' || tok[4] != ' ') + /* bad hex token */ + break; + + rv = hex_from_2char(&tok[2], input->buf.data + j); + if (rv) + break; + } + break; + case bltestHexStream: + SECITEM_AllocItem(arena, &input->buf, in->len/2); + for (i=0, j=0; i<in->len; i+=2, j++) { + tok = &in->data[i]; + rv = hex_from_2char(tok, input->buf.data + j); + if (rv) + break; + } + break; + } + + if (file) + SECITEM_FreeItem(&fileData, PR_FALSE); + return rv; +} + +SECStatus +finishIO(bltestIO *output, PRFileDesc *file) +{ + SECStatus rv = SECSuccess; + PRInt32 nb; + unsigned char byteval; + SECItem *it; + char hexstr[5]; + unsigned int i; + if (output->pBuf.len > 0) { + it = &output->pBuf; + } else { + it = &output->buf; + } + switch (output->mode) { + case bltestBase64Encoded: + rv = btoa_file(it, file); + break; + case bltestBinary: + nb = PR_Write(file, it->data, it->len); + rv = (nb == (PRInt32)it->len) ? SECSuccess : SECFailure; + break; + case bltestHexSpaceDelim: + hexstr[0] = '0'; + hexstr[1] = 'x'; + hexstr[4] = ' '; + for (i=0; i<it->len; i++) { + byteval = it->data[i]; + rv = char2_from_hex(byteval, hexstr + 2); + nb = PR_Write(file, hexstr, 5); + if (rv) + break; + } + PR_Write(file, "\n", 1); + break; + case bltestHexStream: + for (i=0; i<it->len; i++) { + byteval = it->data[i]; + rv = char2_from_hex(byteval, hexstr); + if (rv) + break; + nb = PR_Write(file, hexstr, 2); + } + PR_Write(file, "\n", 1); + break; + } + return rv; +} + +void +bltestCopyIO(PRArenaPool *arena, bltestIO *dest, bltestIO *src) +{ + SECITEM_CopyItem(arena, &dest->buf, &src->buf); + if (src->pBuf.len > 0) { + dest->pBuf.len = src->pBuf.len; + dest->pBuf.data = dest->buf.data + (src->pBuf.data - src->buf.data); + } + dest->mode = src->mode; + dest->file = src->file; +} + +void +misalignBuffer(PRArenaPool *arena, bltestIO *io, int off) +{ + ptrdiff_t offset = (ptrdiff_t)io->buf.data % WORDSIZE; + int length = io->buf.len; + if (offset != off) { + SECITEM_ReallocItem(arena, &io->buf, length, length + 2*WORDSIZE); + io->buf.len = length + 2*WORDSIZE; /* why doesn't realloc do this? */ + /* offset may have changed? */ + offset = (ptrdiff_t)io->buf.data % WORDSIZE; + if (offset != off) { + memmove(io->buf.data + off, io->buf.data, length); + io->pBuf.data = io->buf.data + off; + io->pBuf.len = length; + } else { + io->pBuf.data = io->buf.data; + io->pBuf.len = length; + } + } else { + io->pBuf.data = io->buf.data; + io->pBuf.len = length; + } +} + +SECStatus +des_Encrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return DES_Encrypt((DESContext *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} + +SECStatus +des_Decrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return DES_Decrypt((DESContext *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} + +SECStatus +rc2_Encrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return RC2_Encrypt((RC2Context *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} + +SECStatus +rc2_Decrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return RC2_Decrypt((RC2Context *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} + +SECStatus +rc4_Encrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return RC4_Encrypt((RC4Context *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} + +SECStatus +rc4_Decrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return RC4_Decrypt((RC4Context *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} + +SECStatus +aes_Encrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return AES_Encrypt((AESContext *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} + +SECStatus +aes_Decrypt(void *cx, unsigned char *output, unsigned int *outputLen, + unsigned int maxOutputLen, const unsigned char *input, + unsigned int inputLen) +{ + return AES_Decrypt((AESContext *)cx, output, outputLen, maxOutputLen, + input, inputLen); +} + +SECStatus +rsa_PublicKeyOp(void *key, SECItem *output, const SECItem *input) +{ + return RSA_PublicKeyOp((RSAPublicKey *)key, output->data, input->data); +} + +SECStatus +rsa_PrivateKeyOp(void *key, SECItem *output, const SECItem *input) +{ + return RSA_PrivateKeyOp((RSAPrivateKey *)key, output->data, input->data); +} + +SECStatus +dsa_signDigest(void *key, SECItem *output, const SECItem *input) +{ + return DSA_SignDigest((DSAPrivateKey *)key, output, input); +} + +SECStatus +dsa_verifyDigest(void *key, SECItem *output, const SECItem *input) +{ + return DSA_VerifyDigest((DSAPublicKey *)key, output, input); +} + +SECStatus +bltest_des_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + PRIntervalTime time1, time2; + bltestSymmKeyParams *desp = &cipherInfo->params.sk; + int minorMode; + int i; + switch (cipherInfo->mode) { + case bltestDES_ECB: minorMode = NSS_DES; break; + case bltestDES_CBC: minorMode = NSS_DES_CBC; break; + case bltestDES_EDE_ECB: minorMode = NSS_DES_EDE3; break; + case bltestDES_EDE_CBC: minorMode = NSS_DES_EDE3_CBC; break; + default: + return SECFailure; + } + cipherInfo->cx = (void*)DES_CreateContext(desp->key.buf.data, + desp->iv.buf.data, + minorMode, encrypt); + if (cipherInfo->cxreps > 0) { + DESContext **dummycx; + dummycx = PORT_Alloc(cipherInfo->cxreps * sizeof(DESContext *)); + TIMESTART(); + for (i=0; i<cipherInfo->cxreps; i++) { + dummycx[i] = (void*)DES_CreateContext(desp->key.buf.data, + desp->iv.buf.data, + minorMode, encrypt); + } + TIMEFINISH(cipherInfo->cxtime, 1.0); + for (i=0; i<cipherInfo->cxreps; i++) { + DES_DestroyContext(dummycx[i], PR_TRUE); + } + PORT_Free(dummycx); + } + if (encrypt) + cipherInfo->cipher.symmkeyCipher = des_Encrypt; + else + cipherInfo->cipher.symmkeyCipher = des_Decrypt; + return SECSuccess; +} + +SECStatus +bltest_rc2_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + PRIntervalTime time1, time2; + bltestSymmKeyParams *rc2p = &cipherInfo->params.sk; + int minorMode; + int i; + switch (cipherInfo->mode) { + case bltestRC2_ECB: minorMode = NSS_RC2; break; + case bltestRC2_CBC: minorMode = NSS_RC2_CBC; break; + default: + return SECFailure; + } + cipherInfo->cx = (void*)RC2_CreateContext(rc2p->key.buf.data, + rc2p->key.buf.len, + rc2p->iv.buf.data, + minorMode, + rc2p->key.buf.len); + if (cipherInfo->cxreps > 0) { + RC2Context **dummycx; + dummycx = PORT_Alloc(cipherInfo->cxreps * sizeof(RC2Context *)); + TIMESTART(); + for (i=0; i<cipherInfo->cxreps; i++) { + dummycx[i] = (void*)RC2_CreateContext(rc2p->key.buf.data, + rc2p->key.buf.len, + rc2p->iv.buf.data, + minorMode, + rc2p->key.buf.len); + } + TIMEFINISH(cipherInfo->cxtime, 1.0); + for (i=0; i<cipherInfo->cxreps; i++) { + RC2_DestroyContext(dummycx[i], PR_TRUE); + } + PORT_Free(dummycx); + } + if (encrypt) + cipherInfo->cipher.symmkeyCipher = rc2_Encrypt; + else + cipherInfo->cipher.symmkeyCipher = rc2_Decrypt; + return SECSuccess; +} + +SECStatus +bltest_rc4_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + PRIntervalTime time1, time2; + int i; + bltestSymmKeyParams *rc4p = &cipherInfo->params.sk; + cipherInfo->cx = (void*)RC4_CreateContext(rc4p->key.buf.data, + rc4p->key.buf.len); + if (cipherInfo->cxreps > 0) { + RC4Context **dummycx; + dummycx = PORT_Alloc(cipherInfo->cxreps * sizeof(RC4Context *)); + TIMESTART(); + for (i=0; i<cipherInfo->cxreps; i++) { + dummycx[i] = (void*)RC4_CreateContext(rc4p->key.buf.data, + rc4p->key.buf.len); + } + TIMEFINISH(cipherInfo->cxtime, 1.0); + for (i=0; i<cipherInfo->cxreps; i++) { + RC4_DestroyContext(dummycx[i], PR_TRUE); + } + PORT_Free(dummycx); + } + if (encrypt) + cipherInfo->cipher.symmkeyCipher = rc4_Encrypt; + else + cipherInfo->cipher.symmkeyCipher = rc4_Decrypt; + return SECSuccess; +} + +SECStatus +bltest_rc5_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ +#if NSS_SOFTOKEN_DOES_RC5 + PRIntervalTime time1, time2; + bltestRC5Params *rc5p = &cipherInfo->params.rc5; + int minorMode; + switch (cipherInfo->mode) { + case bltestRC5_ECB: minorMode = NSS_RC5; break; + case bltestRC5_CBC: minorMode = NSS_RC5_CBC; break; + default: + return SECFailure; + } + TIMESTART(); + cipherInfo->cx = (void*)RC5_CreateContext(&rc5p->key.buf, + rc5p->rounds, rc5p->wordsize, + rc5p->iv.buf.data, minorMode); + TIMEFINISH(cipherInfo->cxtime, 1.0); + if (encrypt) + cipherInfo->cipher.symmkeyCipher = RC5_Encrypt; + else + cipherInfo->cipher.symmkeyCipher = RC5_Decrypt; + return SECSuccess; +#else + return SECFailure; +#endif +} + +SECStatus +bltest_aes_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + PRIntervalTime time1, time2; + bltestSymmKeyParams *aesp = &cipherInfo->params.sk; + int minorMode; + int i; + /* XXX */ int keylen, blocklen; + keylen = aesp->key.buf.len; + blocklen = cipherInfo->input.pBuf.len; + switch (cipherInfo->mode) { + case bltestAES_ECB: minorMode = NSS_AES; break; + case bltestAES_CBC: minorMode = NSS_AES_CBC; break; + default: + return SECFailure; + } + cipherInfo->cx = (void*)AES_CreateContext(aesp->key.buf.data, + aesp->iv.buf.data, + minorMode, encrypt, + keylen, blocklen); + if (cipherInfo->cxreps > 0) { + AESContext **dummycx; + dummycx = PORT_Alloc(cipherInfo->cxreps * sizeof(AESContext *)); + TIMESTART(); + for (i=0; i<cipherInfo->cxreps; i++) { + dummycx[i] = (void*)AES_CreateContext(aesp->key.buf.data, + aesp->iv.buf.data, + minorMode, encrypt, + keylen, blocklen); + } + TIMEFINISH(cipherInfo->cxtime, 1.0); + for (i=0; i<cipherInfo->cxreps; i++) { + AES_DestroyContext(dummycx[i], PR_TRUE); + } + PORT_Free(dummycx); + } + if (encrypt) + cipherInfo->cipher.symmkeyCipher = aes_Encrypt; + else + cipherInfo->cipher.symmkeyCipher = aes_Decrypt; + return SECSuccess; +} + +SECStatus +bltest_rsa_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + int i; + RSAPrivateKey **dummyKey; + PRIntervalTime time1, time2; + bltestRSAParams *rsap = &cipherInfo->params.rsa; + /* RSA key gen was done during parameter setup */ + cipherInfo->cx = cipherInfo->params.rsa.rsakey; + /* For performance testing */ + if (cipherInfo->cxreps > 0) { + /* Create space for n private key objects */ + dummyKey = (RSAPrivateKey **)PORT_Alloc(cipherInfo->cxreps * + sizeof(RSAPrivateKey *)); + /* Time n keygens, storing in the array */ + TIMESTART(); + for (i=0; i<cipherInfo->cxreps; i++) + dummyKey[i] = RSA_NewKey(rsap->keysizeInBits, + &rsap->rsakey->publicExponent); + TIMEFINISH(cipherInfo->cxtime, cipherInfo->cxreps); + /* Free the n key objects */ + for (i=0; i<cipherInfo->cxreps; i++) + PORT_FreeArena(dummyKey[i]->arena, PR_TRUE); + PORT_Free(dummyKey); + } + if (encrypt) { + /* Have to convert private key to public key. Memory + * is freed with private key's arena */ + RSAPublicKey *pubkey; + RSAPrivateKey *key = (RSAPrivateKey *)cipherInfo->cx; + pubkey = (RSAPublicKey *)PORT_ArenaAlloc(key->arena, + sizeof(RSAPublicKey)); + pubkey->modulus.len = key->modulus.len; + pubkey->modulus.data = key->modulus.data; + pubkey->publicExponent.len = key->publicExponent.len; + pubkey->publicExponent.data = key->publicExponent.data; + cipherInfo->cx = (void *)pubkey; + cipherInfo->cipher.pubkeyCipher = rsa_PublicKeyOp; + } else { + cipherInfo->cipher.pubkeyCipher = rsa_PrivateKeyOp; + } + return SECSuccess; +} + +SECStatus +bltest_pqg_init(bltestDSAParams *dsap) +{ + SECStatus rv, res; + PQGVerify *vfy = NULL; + rv = PQG_ParamGen(dsap->j, &dsap->pqg, &vfy); + CHECKERROR(rv, __LINE__); + rv = PQG_VerifyParams(dsap->pqg, vfy, &res); + CHECKERROR(res, __LINE__); + CHECKERROR(rv, __LINE__); + return rv; +} + +SECStatus +bltest_dsa_init(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + int i; + DSAPrivateKey **dummyKey; + PQGParams *dummypqg; + PRIntervalTime time1, time2; + bltestDSAParams *dsap = &cipherInfo->params.dsa; + PQGVerify *ignore = NULL; + /* DSA key gen was done during parameter setup */ + cipherInfo->cx = cipherInfo->params.dsa.dsakey; + /* For performance testing */ + if (cipherInfo->cxreps > 0) { + /* Create space for n private key objects */ + dummyKey = (DSAPrivateKey **)PORT_ZAlloc(cipherInfo->cxreps * + sizeof(DSAPrivateKey *)); + /* Time n keygens, storing in the array */ + TIMESTART(); + for (i=0; i<cipherInfo->cxreps; i++) { + dummypqg = NULL; + PQG_ParamGen(dsap->j, &dummypqg, &ignore); + DSA_NewKey(dummypqg, &dummyKey[i]); + } + TIMEFINISH(cipherInfo->cxtime, cipherInfo->cxreps); + /* Free the n key objects */ + for (i=0; i<cipherInfo->cxreps; i++) + PORT_FreeArena(dummyKey[i]->params.arena, PR_TRUE); + PORT_Free(dummyKey); + } + if (!dsap->pqg && dsap->pqgdata.buf.len > 0) { + dsap->pqg = pqg_from_filedata(&dsap->pqgdata.buf); + } + if (!cipherInfo->cx && dsap->key.buf.len > 0) { + cipherInfo->cx = dsakey_from_filedata(&dsap->key.buf); + } + if (encrypt) { + cipherInfo->cipher.pubkeyCipher = dsa_signDigest; + } else { + /* Have to convert private key to public key. Memory + * is freed with private key's arena */ + DSAPublicKey *pubkey; + DSAPrivateKey *key = (DSAPrivateKey *)cipherInfo->cx; + pubkey = (DSAPublicKey *)PORT_ArenaZAlloc(key->params.arena, + sizeof(DSAPublicKey)); + pubkey->params.prime.len = key->params.prime.len; + pubkey->params.prime.data = key->params.prime.data; + pubkey->params.subPrime.len = key->params.subPrime.len; + pubkey->params.subPrime.data = key->params.subPrime.data; + pubkey->params.base.len = key->params.base.len; + pubkey->params.base.data = key->params.base.data; + pubkey->publicValue.len = key->publicValue.len; + pubkey->publicValue.data = key->publicValue.data; + cipherInfo->cipher.pubkeyCipher = dsa_verifyDigest; + } + return SECSuccess; +} + +/* XXX unfortunately, this is not defined in blapi.h */ +SECStatus +md2_HashBuf(unsigned char *dest, const unsigned char *src, uint32 src_length) +{ + unsigned int len; + MD2Context *cx = MD2_NewContext(); + if (cx == NULL) return SECFailure; + MD2_Begin(cx); + MD2_Update(cx, src, src_length); + MD2_End(cx, dest, &len, MD2_LENGTH); + MD2_DestroyContext(cx, PR_TRUE); + return SECSuccess; +} + +SECStatus +md2_restart(unsigned char *dest, const unsigned char *src, uint32 src_length) +{ + MD2Context *cx, *cx_cpy; + unsigned char *cxbytes; + unsigned int len; + unsigned int i, quarter; + SECStatus rv = SECSuccess; + cx = MD2_NewContext(); + MD2_Begin(cx); + /* divide message by 4, restarting 3 times */ + quarter = (src_length + 3)/ 4; + for (i=0; i < 4 && src_length > 0; i++) { + MD2_Update(cx, src + i*quarter, PR_MIN(quarter, src_length)); + len = MD2_FlattenSize(cx); + cxbytes = PORT_Alloc(len); + MD2_Flatten(cx, cxbytes); + cx_cpy = MD2_Resurrect(cxbytes, NULL); + if (!cx_cpy) { + PR_fprintf(PR_STDERR, "%s: MD2_Resurrect failed!\n", progName); + goto finish; + } + rv = PORT_Memcmp(cx, cx_cpy, len); + if (rv) { + MD2_DestroyContext(cx_cpy, PR_TRUE); + PR_fprintf(PR_STDERR, "%s: MD2_restart failed!\n", progName); + goto finish; + } + MD2_DestroyContext(cx_cpy, PR_TRUE); + PORT_Free(cxbytes); + src_length -= quarter; + } + MD2_End(cx, dest, &len, MD2_LENGTH); +finish: + MD2_DestroyContext(cx, PR_TRUE); + return rv; +} + +SECStatus +md5_restart(unsigned char *dest, const unsigned char *src, uint32 src_length) +{ + SECStatus rv = SECSuccess; + MD5Context *cx, *cx_cpy; + unsigned char *cxbytes; + unsigned int len; + unsigned int i, quarter; + cx = MD5_NewContext(); + MD5_Begin(cx); + /* divide message by 4, restarting 3 times */ + quarter = (src_length + 3)/ 4; + for (i=0; i < 4 && src_length > 0; i++) { + MD5_Update(cx, src + i*quarter, PR_MIN(quarter, src_length)); + len = MD5_FlattenSize(cx); + cxbytes = PORT_Alloc(len); + MD5_Flatten(cx, cxbytes); + cx_cpy = MD5_Resurrect(cxbytes, NULL); + if (!cx_cpy) { + PR_fprintf(PR_STDERR, "%s: MD5_Resurrect failed!\n", progName); + rv = SECFailure; + goto finish; + } + rv = PORT_Memcmp(cx, cx_cpy, len); + if (rv) { + MD5_DestroyContext(cx_cpy, PR_TRUE); + PR_fprintf(PR_STDERR, "%s: MD5_restart failed!\n", progName); + goto finish; + } + MD5_DestroyContext(cx_cpy, PR_TRUE); + PORT_Free(cxbytes); + src_length -= quarter; + } + MD5_End(cx, dest, &len, MD5_LENGTH); +finish: + MD5_DestroyContext(cx, PR_TRUE); + return rv; +} + +SECStatus +sha1_restart(unsigned char *dest, const unsigned char *src, uint32 src_length) +{ + SECStatus rv = SECSuccess; + SHA1Context *cx, *cx_cpy; + unsigned char *cxbytes; + unsigned int len; + unsigned int i, quarter; + cx = SHA1_NewContext(); + SHA1_Begin(cx); + /* divide message by 4, restarting 3 times */ + quarter = (src_length + 3)/ 4; + for (i=0; i < 4 && src_length > 0; i++) { + SHA1_Update(cx, src + i*quarter, PR_MIN(quarter, src_length)); + len = SHA1_FlattenSize(cx); + cxbytes = PORT_Alloc(len); + SHA1_Flatten(cx, cxbytes); + cx_cpy = SHA1_Resurrect(cxbytes, NULL); + if (!cx_cpy) { + PR_fprintf(PR_STDERR, "%s: SHA1_Resurrect failed!\n", progName); + rv = SECFailure; + goto finish; + } + rv = PORT_Memcmp(cx, cx_cpy, len); + if (rv) { + SHA1_DestroyContext(cx_cpy, PR_TRUE); + PR_fprintf(PR_STDERR, "%s: SHA1_restart failed!\n", progName); + goto finish; + } + SHA1_DestroyContext(cx_cpy, PR_TRUE); + PORT_Free(cxbytes); + src_length -= quarter; + } + SHA1_End(cx, dest, &len, MD5_LENGTH); +finish: + SHA1_DestroyContext(cx, PR_TRUE); + return rv; +} + +SECStatus +SHA256_restart(unsigned char *dest, const unsigned char *src, uint32 src_length) +{ + SECStatus rv = SECSuccess; + SHA256Context *cx, *cx_cpy; + unsigned char *cxbytes; + unsigned int len; + unsigned int i, quarter; + cx = SHA256_NewContext(); + SHA256_Begin(cx); + /* divide message by 4, restarting 3 times */ + quarter = (src_length + 3)/ 4; + for (i=0; i < 4 && src_length > 0; i++) { + SHA256_Update(cx, src + i*quarter, PR_MIN(quarter, src_length)); + len = SHA256_FlattenSize(cx); + cxbytes = PORT_Alloc(len); + SHA256_Flatten(cx, cxbytes); + cx_cpy = SHA256_Resurrect(cxbytes, NULL); + if (!cx_cpy) { + PR_fprintf(PR_STDERR, "%s: SHA256_Resurrect failed!\n", progName); + rv = SECFailure; + goto finish; + } + rv = PORT_Memcmp(cx, cx_cpy, len); + if (rv) { + SHA256_DestroyContext(cx_cpy, PR_TRUE); + PR_fprintf(PR_STDERR, "%s: SHA256_restart failed!\n", progName); + goto finish; + } + SHA256_DestroyContext(cx_cpy, PR_TRUE); + PORT_Free(cxbytes); + src_length -= quarter; + } + SHA256_End(cx, dest, &len, MD5_LENGTH); +finish: + SHA256_DestroyContext(cx, PR_TRUE); + return rv; +} + +SECStatus +SHA384_restart(unsigned char *dest, const unsigned char *src, uint32 src_length) +{ + SECStatus rv = SECSuccess; + SHA384Context *cx, *cx_cpy; + unsigned char *cxbytes; + unsigned int len; + unsigned int i, quarter; + cx = SHA384_NewContext(); + SHA384_Begin(cx); + /* divide message by 4, restarting 3 times */ + quarter = (src_length + 3)/ 4; + for (i=0; i < 4 && src_length > 0; i++) { + SHA384_Update(cx, src + i*quarter, PR_MIN(quarter, src_length)); + len = SHA384_FlattenSize(cx); + cxbytes = PORT_Alloc(len); + SHA384_Flatten(cx, cxbytes); + cx_cpy = SHA384_Resurrect(cxbytes, NULL); + if (!cx_cpy) { + PR_fprintf(PR_STDERR, "%s: SHA384_Resurrect failed!\n", progName); + rv = SECFailure; + goto finish; + } + rv = PORT_Memcmp(cx, cx_cpy, len); + if (rv) { + SHA384_DestroyContext(cx_cpy, PR_TRUE); + PR_fprintf(PR_STDERR, "%s: SHA384_restart failed!\n", progName); + goto finish; + } + SHA384_DestroyContext(cx_cpy, PR_TRUE); + PORT_Free(cxbytes); + src_length -= quarter; + } + SHA384_End(cx, dest, &len, MD5_LENGTH); +finish: + SHA384_DestroyContext(cx, PR_TRUE); + return rv; +} + +SECStatus +SHA512_restart(unsigned char *dest, const unsigned char *src, uint32 src_length) +{ + SECStatus rv = SECSuccess; + SHA512Context *cx, *cx_cpy; + unsigned char *cxbytes; + unsigned int len; + unsigned int i, quarter; + cx = SHA512_NewContext(); + SHA512_Begin(cx); + /* divide message by 4, restarting 3 times */ + quarter = (src_length + 3)/ 4; + for (i=0; i < 4 && src_length > 0; i++) { + SHA512_Update(cx, src + i*quarter, PR_MIN(quarter, src_length)); + len = SHA512_FlattenSize(cx); + cxbytes = PORT_Alloc(len); + SHA512_Flatten(cx, cxbytes); + cx_cpy = SHA512_Resurrect(cxbytes, NULL); + if (!cx_cpy) { + PR_fprintf(PR_STDERR, "%s: SHA512_Resurrect failed!\n", progName); + rv = SECFailure; + goto finish; + } + rv = PORT_Memcmp(cx, cx_cpy, len); + if (rv) { + SHA512_DestroyContext(cx_cpy, PR_TRUE); + PR_fprintf(PR_STDERR, "%s: SHA512_restart failed!\n", progName); + goto finish; + } + SHA512_DestroyContext(cx_cpy, PR_TRUE); + PORT_Free(cxbytes); + src_length -= quarter; + } + SHA512_End(cx, dest, &len, MD5_LENGTH); +finish: + SHA512_DestroyContext(cx, PR_TRUE); + return rv; +} + +SECStatus +pubkeyInitKey(bltestCipherInfo *cipherInfo, PRFileDesc *file, + int keysize, int exponent) +{ + int i; + SECStatus rv = SECSuccess; + bltestRSAParams *rsap; + bltestDSAParams *dsap; + switch (cipherInfo->mode) { + case bltestRSA: + rsap = &cipherInfo->params.rsa; + if (keysize > 0) { + SECItem expitem = { 0, 0, 0 }; + SECITEM_AllocItem(cipherInfo->arena, &expitem, sizeof(int)); + for (i = 1; i <= sizeof(int); i++) + expitem.data[i-1] = exponent >> (8*(sizeof(int) - i)); + rsap->rsakey = RSA_NewKey(keysize * 8, &expitem); + serialize_key(&rsap->rsakey->version, 9, file); + rsap->keysizeInBits = keysize * 8; + } else { + setupIO(cipherInfo->arena, &cipherInfo->params.key, file, NULL, 0); + rsap->rsakey = rsakey_from_filedata(&cipherInfo->params.key.buf); + rsap->keysizeInBits = rsap->rsakey->modulus.len * 8; + } + break; + case bltestDSA: + dsap = &cipherInfo->params.dsa; + if (keysize > 0) { + dsap->j = PQG_PBITS_TO_INDEX(8*keysize); + if (!dsap->pqg) + bltest_pqg_init(dsap); + rv = DSA_NewKey(dsap->pqg, &dsap->dsakey); + CHECKERROR(rv, __LINE__); + serialize_key(&dsap->dsakey->params.prime, 5, file); + } else { + setupIO(cipherInfo->arena, &cipherInfo->params.key, file, NULL, 0); + dsap->dsakey = dsakey_from_filedata(&cipherInfo->params.key.buf); + dsap->j = PQG_PBITS_TO_INDEX(8*dsap->dsakey->params.prime.len); + } + break; + default: + return SECFailure; + } + return SECSuccess; +} + +SECStatus +cipherInit(bltestCipherInfo *cipherInfo, PRBool encrypt) +{ + PRBool restart; + switch (cipherInfo->mode) { + case bltestDES_ECB: + case bltestDES_CBC: + case bltestDES_EDE_ECB: + case bltestDES_EDE_CBC: + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + cipherInfo->input.pBuf.len); + return bltest_des_init(cipherInfo, encrypt); + break; + case bltestRC2_ECB: + case bltestRC2_CBC: + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + cipherInfo->input.pBuf.len); + return bltest_rc2_init(cipherInfo, encrypt); + break; + case bltestRC4: + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + cipherInfo->input.pBuf.len); + return bltest_rc4_init(cipherInfo, encrypt); + break; + case bltestRC5_ECB: + case bltestRC5_CBC: +#if NSS_SOFTOKEN_DOES_RC5 + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + cipherInfo->input.pBuf.len); +#endif + return bltest_rc5_init(cipherInfo, encrypt); + break; + case bltestAES_ECB: + case bltestAES_CBC: + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + cipherInfo->input.pBuf.len); + return bltest_aes_init(cipherInfo, encrypt); + break; + case bltestRSA: + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + cipherInfo->input.pBuf.len); + return bltest_rsa_init(cipherInfo, encrypt); + break; + case bltestDSA: + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + DSA_SIGNATURE_LEN); + return bltest_dsa_init(cipherInfo, encrypt); + break; + case bltestMD2: + restart = cipherInfo->params.hash.restart; + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + MD2_LENGTH); + cipherInfo->cipher.hashCipher = (restart) ? md2_restart : md2_HashBuf; + return SECSuccess; + break; + case bltestMD5: + restart = cipherInfo->params.hash.restart; + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + MD5_LENGTH); + cipherInfo->cipher.hashCipher = (restart) ? md5_restart : MD5_HashBuf; + return SECSuccess; + break; + case bltestSHA1: + restart = cipherInfo->params.hash.restart; + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + SHA1_LENGTH); + cipherInfo->cipher.hashCipher = (restart) ? sha1_restart : SHA1_HashBuf; + return SECSuccess; + break; + case bltestSHA256: + restart = cipherInfo->params.hash.restart; + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + SHA256_LENGTH); + cipherInfo->cipher.hashCipher = (restart) ? SHA256_restart + : SHA256_HashBuf; + return SECSuccess; + break; + case bltestSHA384: + restart = cipherInfo->params.hash.restart; + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + SHA384_LENGTH); + cipherInfo->cipher.hashCipher = (restart) ? SHA384_restart + : SHA384_HashBuf; + return SECSuccess; + break; + case bltestSHA512: + restart = cipherInfo->params.hash.restart; + SECITEM_AllocItem(cipherInfo->arena, &cipherInfo->output.buf, + SHA512_LENGTH); + cipherInfo->cipher.hashCipher = (restart) ? SHA512_restart + : SHA512_HashBuf; + return SECSuccess; + break; + default: + return SECFailure; + } + return SECSuccess; +} + +SECStatus +dsaOp(bltestCipherInfo *cipherInfo) +{ + PRIntervalTime time1, time2; + SECStatus rv = SECSuccess; + int i; + int maxLen = cipherInfo->output.pBuf.len; + SECItem dummyOut = { 0, 0, 0 }; + SECITEM_AllocItem(NULL, &dummyOut, maxLen); + if (cipherInfo->cipher.pubkeyCipher == dsa_signDigest) { + if (cipherInfo->params.dsa.sigseed.buf.len > 0) { + rv = DSA_SignDigestWithSeed((DSAPrivateKey *)cipherInfo->cx, + &cipherInfo->output.pBuf, + &cipherInfo->input.pBuf, + cipherInfo->params.dsa.sigseed.buf.data); + CHECKERROR(rv, __LINE__); + TIMESTART(); + for (i=0; i<cipherInfo->repetitions; i++) { + rv |= DSA_SignDigestWithSeed((DSAPrivateKey *)cipherInfo->cx, + &dummyOut, + &cipherInfo->input.pBuf, + cipherInfo->params.dsa.sigseed.buf.data); + } + TIMEFINISH(cipherInfo->optime, 1.0); + CHECKERROR(rv, __LINE__); + } else { + rv = DSA_SignDigest((DSAPrivateKey *)cipherInfo->cx, + &cipherInfo->output.pBuf, + &cipherInfo->input.pBuf); + CHECKERROR(rv, __LINE__); + TIMESTART(); + for (i=0; i<cipherInfo->repetitions; i++) { + DSA_SignDigest((DSAPrivateKey *)cipherInfo->cx, &dummyOut, + &cipherInfo->input.pBuf); + } + TIMEFINISH(cipherInfo->optime, 1.0); + } + bltestCopyIO(cipherInfo->arena, &cipherInfo->params.dsa.sig, + &cipherInfo->output); + } else { + rv = DSA_VerifyDigest((DSAPublicKey *)cipherInfo->cx, + &cipherInfo->params.dsa.sig.buf, + &cipherInfo->input.pBuf); + CHECKERROR(rv, __LINE__); + TIMESTART(); + for (i=0; i<cipherInfo->repetitions; i++) { + DSA_VerifyDigest((DSAPublicKey *)cipherInfo->cx, + &cipherInfo->params.dsa.sig.buf, + &cipherInfo->input.pBuf); + } + TIMEFINISH(cipherInfo->optime, 1.0); + } + SECITEM_FreeItem(&dummyOut, PR_FALSE); + return rv; +} + +SECStatus +cipherDoOp(bltestCipherInfo *cipherInfo) +{ + PRIntervalTime time1, time2; + SECStatus rv = SECSuccess; + int i, len; + int maxLen = cipherInfo->output.pBuf.len; + unsigned char *dummyOut; + if (cipherInfo->mode == bltestDSA) + return dsaOp(cipherInfo); + dummyOut = PORT_Alloc(maxLen); + if (is_symmkeyCipher(cipherInfo->mode)) { + rv = (*cipherInfo->cipher.symmkeyCipher)(cipherInfo->cx, + cipherInfo->output.pBuf.data, + &len, maxLen, + cipherInfo->input.pBuf.data, + cipherInfo->input.pBuf.len); + TIMESTART(); + for (i=0; i<cipherInfo->repetitions; i++) { + (*cipherInfo->cipher.symmkeyCipher)(cipherInfo->cx, dummyOut, + &len, maxLen, + cipherInfo->input.pBuf.data, + cipherInfo->input.pBuf.len); + + } + TIMEFINISH(cipherInfo->optime, 1.0); + } else if (is_pubkeyCipher(cipherInfo->mode)) { + rv = (*cipherInfo->cipher.pubkeyCipher)(cipherInfo->cx, + &cipherInfo->output.pBuf, + &cipherInfo->input.pBuf); + TIMESTART(); + for (i=0; i<cipherInfo->repetitions; i++) { + SECItem dummy; + dummy.data = dummyOut; + dummy.len = maxLen; + (*cipherInfo->cipher.pubkeyCipher)(cipherInfo->cx, &dummy, + &cipherInfo->input.pBuf); + } + TIMEFINISH(cipherInfo->optime, 1.0); + } else if (is_hashCipher(cipherInfo->mode)) { + rv = (*cipherInfo->cipher.hashCipher)(cipherInfo->output.pBuf.data, + cipherInfo->input.pBuf.data, + cipherInfo->input.pBuf.len); + TIMESTART(); + for (i=0; i<cipherInfo->repetitions; i++) { + (*cipherInfo->cipher.hashCipher)(dummyOut, + cipherInfo->input.pBuf.data, + cipherInfo->input.pBuf.len); + } + TIMEFINISH(cipherInfo->optime, 1.0); + } + PORT_Free(dummyOut); + return rv; +} + +SECStatus +cipherFinish(bltestCipherInfo *cipherInfo) +{ + switch (cipherInfo->mode) { + case bltestDES_ECB: + case bltestDES_CBC: + case bltestDES_EDE_ECB: + case bltestDES_EDE_CBC: + DES_DestroyContext((DESContext *)cipherInfo->cx, PR_TRUE); + break; + case bltestAES_ECB: + case bltestAES_CBC: + AES_DestroyContext((AESContext *)cipherInfo->cx, PR_TRUE); + break; + case bltestRC2_ECB: + case bltestRC2_CBC: + RC2_DestroyContext((RC2Context *)cipherInfo->cx, PR_TRUE); + break; + case bltestRC4: + RC4_DestroyContext((RC4Context *)cipherInfo->cx, PR_TRUE); + break; +#if NSS_SOFTOKEN_DOES_RC5 + case bltestRC5_ECB: + case bltestRC5_CBC: + RC5_DestroyContext((RC5Context *)cipherInfo->cx, PR_TRUE); + break; +#endif + case bltestRSA: /* keys are alloc'ed within cipherInfo's arena, */ + case bltestDSA: /* will be freed with it. */ + case bltestMD2: /* hash contexts are ephemeral */ + case bltestMD5: + case bltestSHA1: + case bltestSHA256: + case bltestSHA384: + case bltestSHA512: + return SECSuccess; + break; + default: + return SECFailure; + } + return SECSuccess; +} + +void +print_exponent(SECItem *exp) +{ + int i; + int e = 0; + if (exp->len <= 4) { + for (i=exp->len; i >=0; --i) e |= exp->data[exp->len-i] << 8*(i-1); + fprintf(stdout, "%12d", e); + } else { + e = 8*exp->len; + fprintf(stdout, "~2**%-8d", e); + } +} + +void +dump_performance_info(bltestCipherInfo *info, PRBool encrypt, PRBool cxonly) +{ + PRBool td = PR_TRUE; + fprintf(stdout, "#%9s", "mode"); + fprintf(stdout, "%12s", "in"); +print_td: + switch (info->mode) { + case bltestDES_ECB: + case bltestDES_CBC: + case bltestDES_EDE_ECB: + case bltestDES_EDE_CBC: + case bltestAES_ECB: + case bltestAES_CBC: + case bltestRC2_ECB: + case bltestRC2_CBC: + case bltestRC4: + if (td) + fprintf(stdout, "%8s", "symmkey"); + else + fprintf(stdout, "%8d", 8*info->params.sk.key.buf.len); + break; +#if NSS_SOFTOKEN_DOES_RC5 + case bltestRC5_ECB: + case bltestRC5_CBC: + if (info->params.sk.key.buf.len > 0) + printf("symmetric key(bytes)=%d,", info->params.sk.key.buf.len); + if (info->rounds > 0) + printf("rounds=%d,", info->params.rc5.rounds); + if (info->wordsize > 0) + printf("wordsize(bytes)=%d,", info->params.rc5.wordsize); + break; +#endif + case bltestRSA: + if (td) { + fprintf(stdout, "%8s", "rsa_mod"); + fprintf(stdout, "%12s", "rsa_pe"); + } else { + fprintf(stdout, "%8d", info->params.rsa.keysizeInBits); + print_exponent(&info->params.rsa.rsakey->publicExponent); + } + break; + case bltestDSA: + if (td) + fprintf(stdout, "%8s", "pqg_mod"); + else + fprintf(stdout, "%8d", PQG_INDEX_TO_PBITS(info->params.dsa.j)); + break; + case bltestMD2: + case bltestMD5: + case bltestSHA1: + case bltestSHA256: + case bltestSHA384: + case bltestSHA512: + default: + break; + } + if (!td) { + fprintf(stdout, "%8d", info->repetitions); + fprintf(stdout, "%8d", info->cxreps); + fprintf(stdout, "%12.3f", info->cxtime); + fprintf(stdout, "%12.3f", info->optime); + fprintf(stdout, "\n"); + return; + } + + fprintf(stdout, "%8s", "opreps"); + fprintf(stdout, "%8s", "cxreps"); + fprintf(stdout, "%12s", "context"); + fprintf(stdout, "%12s", "op"); + fprintf(stdout, "\n"); + fprintf(stdout, "%8s", mode_strings[info->mode]); + fprintf(stdout, "_%c", (cxonly) ? 'c' : (encrypt) ? 'e' : 'd'); + fprintf(stdout, "%12d", info->input.buf.len * info->repetitions); + + td = !td; + goto print_td; +} + +void +printmodes() +{ + bltestCipherMode mode; + int nummodes = sizeof(mode_strings) / sizeof(char *); + fprintf(stderr, "%s: Available modes (specify with -m):\n", progName); + for (mode=0; mode<nummodes; mode++) + fprintf(stderr, "%s\n", mode_strings[mode]); +} + +bltestCipherMode +get_mode(const char *modestring) +{ + bltestCipherMode mode; + int nummodes = sizeof(mode_strings) / sizeof(char *); + for (mode=0; mode<nummodes; mode++) + if (PL_strcmp(modestring, mode_strings[mode]) == 0) + return mode; + fprintf(stderr, "%s: invalid mode: %s\n", progName, modestring); + return bltestINVALID; +} + +void +load_file_data(PRArenaPool *arena, bltestIO *data, + char *fn, bltestIOMode ioMode) +{ + PRFileDesc *file; + data->mode = ioMode; + data->file = NULL; /* don't use -- not saving anything */ + data->pBuf.data = NULL; + data->pBuf.len = 0; + file = PR_Open(fn, PR_RDONLY, 00660); + if (file) + setupIO(arena, data, file, NULL, 0); +} + +void +get_params(PRArenaPool *arena, bltestParams *params, + bltestCipherMode mode, int j) +{ + char filename[256]; + char *modestr = mode_strings[mode]; +#if NSS_SOFTOKEN_DOES_RC5 + FILE *file; + char *mark, *param, *val; + int index = 0; +#endif + switch (mode) { + case bltestDES_CBC: + case bltestDES_EDE_CBC: + case bltestRC2_CBC: + case bltestAES_CBC: + sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "iv", j); + load_file_data(arena, ¶ms->sk.iv, filename, bltestBinary); + case bltestDES_ECB: + case bltestDES_EDE_ECB: + case bltestRC2_ECB: + case bltestRC4: + case bltestAES_ECB: + sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "key", j); + load_file_data(arena, ¶ms->sk.key, filename, bltestBinary); + break; +#if NSS_SOFTOKEN_DOES_RC5 + case bltestRC5_ECB: + case bltestRC5_CBC: + sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "iv", j); + load_file_data(arena, ¶ms->sk.iv, filename, bltestBinary); + sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "key", j); + load_file_data(arena, ¶ms->sk.key, filename, bltestBinary); + sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, + "params", j); + file = fopen(filename, "r"); + if (!file) return; + param = malloc(100); + len = fread(param, 1, 100, file); + while (index < len) { + mark = PL_strchr(param, '='); + *mark = '\0'; + val = mark + 1; + mark = PL_strchr(val, '\n'); + *mark = '\0'; + if (PL_strcmp(param, "rounds") == 0) { + params->rc5.rounds = atoi(val); + } else if (PL_strcmp(param, "wordsize") == 0) { + params->rc5.wordsize = atoi(val); + } + index += PL_strlen(param) + PL_strlen(val) + 2; + param = mark + 1; + } + break; +#endif + case bltestRSA: + sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "key", j); + load_file_data(arena, ¶ms->rsa.key, filename, bltestBase64Encoded); + params->rsa.rsakey = rsakey_from_filedata(¶ms->key.buf); + break; + case bltestDSA: + sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "key", j); + load_file_data(arena, ¶ms->dsa.key, filename, bltestBase64Encoded); + params->dsa.dsakey = dsakey_from_filedata(¶ms->key.buf); + sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "pqg", j); + load_file_data(arena, ¶ms->dsa.pqgdata, filename, + bltestBase64Encoded); + params->dsa.pqg = pqg_from_filedata(¶ms->dsa.pqgdata.buf); + sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "keyseed", j); + load_file_data(arena, ¶ms->dsa.keyseed, filename, + bltestBase64Encoded); + sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "sigseed", j); + load_file_data(arena, ¶ms->dsa.sigseed, filename, + bltestBase64Encoded); + sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, "ciphertext",j); + load_file_data(arena, ¶ms->dsa.sig, filename, bltestBase64Encoded); + break; + case bltestMD2: + case bltestMD5: + case bltestSHA1: + case bltestSHA256: + case bltestSHA384: + case bltestSHA512: + /*params->hash.restart = PR_TRUE;*/ + params->hash.restart = PR_FALSE; + break; + default: + break; + } +} + +SECStatus +verify_self_test(bltestIO *result, bltestIO *cmp, bltestCipherMode mode, + PRBool forward, SECStatus sigstatus) +{ + int res; + char *modestr = mode_strings[mode]; + res = SECITEM_CompareItem(&result->pBuf, &cmp->buf); + if (is_sigCipher(mode)) { + if (forward) { + if (res == 0) { + printf("Signature self-test for %s passed.\n", modestr); + } else { + printf("Signature self-test for %s failed!\n", modestr); + } + } else { + if (sigstatus == SECSuccess) { + printf("Verification self-test for %s passed.\n", modestr); + } else { + printf("Verification self-test for %s failed!\n", modestr); + } + } + return sigstatus; + } else if (is_hashCipher(mode)) { + if (res == 0) { + printf("Hash self-test for %s passed.\n", modestr); + } else { + printf("Hash self-test for %s failed!\n", modestr); + } + } else { + if (forward) { + if (res == 0) { + printf("Encryption self-test for %s passed.\n", modestr); + } else { + printf("Encryption self-test for %s failed!\n", modestr); + } + } else { + if (res == 0) { + printf("Decryption self-test for %s passed.\n", modestr); + } else { + printf("Decryption self-test for %s failed!\n", modestr); + } + } + } + return (res != 0); +} + +static SECStatus +blapi_selftest(bltestCipherMode *modes, int numModes, int inoff, int outoff, + PRBool encrypt, PRBool decrypt) +{ + bltestCipherInfo cipherInfo; + bltestIO pt, ct; + bltestCipherMode mode; + bltestParams *params; + int i, j, nummodes; + char *modestr; + char filename[256]; + PRFileDesc *file; + PRArenaPool *arena; + SECItem item; + PRBool finished; + SECStatus rv = SECSuccess, srv; + + PORT_Memset(&cipherInfo, 0, sizeof(cipherInfo)); + arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE); + cipherInfo.arena = arena; + + finished = PR_FALSE; + nummodes = (numModes == 0) ? NUMMODES : numModes; + for (i=0; i < nummodes && !finished; i++) { + if (i == bltestRC5_ECB || i == bltestRC5_CBC) continue; + if (numModes > 0) + mode = modes[i]; + else + mode = i; + if (mode == bltestINVALID) { + fprintf(stderr, "%s: Skipping invalid mode.\n",progName); + continue; + } + modestr = mode_strings[mode]; + cipherInfo.mode = mode; + params = &cipherInfo.params; +#ifdef TRACK_BLTEST_BUG + if (mode == bltestRSA) { + fprintf(stderr, "[%s] Self-Testing RSA\n", __bltDBG); + } +#endif + /* get the number of tests in the directory */ + sprintf(filename, "%s/tests/%s/%s", testdir, modestr, "numtests"); + file = PR_Open(filename, PR_RDONLY, 00660); + if (!file) { + fprintf(stderr, "%s: File %s does not exist.\n", progName,filename); + return SECFailure; + } + rv = SECU_FileToItem(&item, file); +#ifdef TRACK_BLTEST_BUG + if (mode == bltestRSA) { + fprintf(stderr, "[%s] Loaded data from %s\n", __bltDBG, filename); + } +#endif + PR_Close(file); + /* loop over the tests in the directory */ + for (j=0; j<(int)(item.data[0] - '0'); j++) { /* XXX bug when > 10 */ +#ifdef TRACK_BLTEST_BUG + if (mode == bltestRSA) { + fprintf(stderr, "[%s] Executing self-test #%d\n", __bltDBG, j); + } +#endif + sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, + "plaintext", j); + load_file_data(arena, &pt, filename, (mode == bltestDSA) ? + bltestBase64Encoded : bltestBinary); + sprintf(filename, "%s/tests/%s/%s%d", testdir, modestr, + "ciphertext", j); + load_file_data(arena, &ct, filename, bltestBase64Encoded); +#ifdef TRACK_BLTEST_BUG + if (mode == bltestRSA) { + fprintf(stderr, "[%s] Loaded data for self-test #%d\n", __bltDBG, j); + } +#endif + get_params(arena, params, mode, j); +#ifdef TRACK_BLTEST_BUG + if (mode == bltestRSA) { + fprintf(stderr, "[%s] Got parameters for #%d\n", __bltDBG, j); + } +#endif + /* Forward Operation (Encrypt/Sign/Hash) + ** Align the input buffer (plaintext) according to request + ** then perform operation and compare to ciphertext + */ + /* XXX for now */ + rv = SECSuccess; + if (encrypt) { + bltestCopyIO(arena, &cipherInfo.input, &pt); + misalignBuffer(arena, &cipherInfo.input, inoff); + memset(&cipherInfo.output.buf, 0, sizeof cipherInfo.output.buf); + rv |= cipherInit(&cipherInfo, PR_TRUE); + misalignBuffer(arena, &cipherInfo.output, outoff); +#ifdef TRACK_BLTEST_BUG + if (mode == bltestRSA) { + fprintf(stderr, "[%s] Inited cipher context and buffers for #%d\n", __bltDBG, j); + } +#endif + rv |= cipherDoOp(&cipherInfo); +#ifdef TRACK_BLTEST_BUG + if (mode == bltestRSA) { + fprintf(stderr, "[%s] Performed encrypt for #%d\n", __bltDBG, j); + } +#endif + rv |= cipherFinish(&cipherInfo); +#ifdef TRACK_BLTEST_BUG + if (mode == bltestRSA) { + fprintf(stderr, "[%s] Finished encrypt for #%d\n", __bltDBG, j); + } +#endif + rv |= verify_self_test(&cipherInfo.output, + &ct, mode, PR_TRUE, 0); +#ifdef TRACK_BLTEST_BUG + if (mode == bltestRSA) { + fprintf(stderr, "[%s] Verified self-test for #%d\n", __bltDBG, j); + } +#endif + /* If testing hash, only one op to test */ + if (is_hashCipher(mode)) + continue; + /*if (rv) return rv;*/ + } + if (!decrypt) + continue; + /* XXX for now */ + rv = SECSuccess; + /* Reverse Operation (Decrypt/Verify) + ** Align the input buffer (ciphertext) according to request + ** then perform operation and compare to plaintext + */ + if (mode != bltestDSA) + bltestCopyIO(arena, &cipherInfo.input, &ct); + else + bltestCopyIO(arena, &cipherInfo.input, &pt); + misalignBuffer(arena, &cipherInfo.input, inoff); + memset(&cipherInfo.output.buf, 0, sizeof cipherInfo.output.buf); + rv |= cipherInit(&cipherInfo, PR_FALSE); + misalignBuffer(arena, &cipherInfo.output, outoff); +#ifdef TRACK_BLTEST_BUG + if (mode == bltestRSA) { + fprintf(stderr, "[%s] Inited cipher context and buffers for #%d\n", __bltDBG, j); + } +#endif + srv = SECSuccess; + srv |= cipherDoOp(&cipherInfo); +#ifdef TRACK_BLTEST_BUG + if (mode == bltestRSA) { + fprintf(stderr, "[%s] Performed decrypt for #%d\n", __bltDBG, j); + } +#endif + rv |= cipherFinish(&cipherInfo); +#ifdef TRACK_BLTEST_BUG + if (mode == bltestRSA) { + fprintf(stderr, "[%s] Finished decrypt for #%d\n", __bltDBG, j); + } +#endif + rv |= verify_self_test(&cipherInfo.output, + &pt, mode, PR_FALSE, srv); +#ifdef TRACK_BLTEST_BUG + if (mode == bltestRSA) { + fprintf(stderr, "[%s] Verified self-test for #%d\n", __bltDBG, j); + } +#endif + /*if (rv) return rv;*/ + } + } + return rv; +} + +SECStatus +dump_file(bltestCipherMode mode, char *filename) +{ + bltestIO keydata; + PRArenaPool *arena = NULL; + arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE); + if (mode == bltestRSA) { + RSAPrivateKey *key; + load_file_data(arena, &keydata, filename, bltestBase64Encoded); + key = rsakey_from_filedata(&keydata.buf); + dump_rsakey(key); + } else if (mode == bltestDSA) { +#if 0 + PQGParams *pqg; + get_file_data(filename, &item, PR_TRUE); + pqg = pqg_from_filedata(&item); + dump_pqg(pqg); +#endif + DSAPrivateKey *key; + load_file_data(arena, &keydata, filename, bltestBase64Encoded); + key = dsakey_from_filedata(&keydata.buf); + dump_dsakey(key); + } + PORT_FreeArena(arena, PR_FALSE); + return SECFailure; +} + +/* bltest commands */ +enum { + cmd_Decrypt = 0, + cmd_Encrypt, + cmd_FIPS, + cmd_Hash, + cmd_Nonce, + cmd_Dump, + cmd_Sign, + cmd_SelfTest, + cmd_Verify +}; + +/* bltest options */ +enum { + opt_B64 = 0, + opt_BufSize, + opt_Restart, + opt_SelfTestDir, + opt_Exponent, + opt_SigFile, + opt_KeySize, + opt_Hex, + opt_Input, + opt_PQGFile, + opt_Key, + opt_HexWSpc, + opt_Mode, + opt_Output, + opt_Repetitions, + opt_ZeroBuf, + opt_Rounds, + opt_Seed, + opt_SigSeedFile, + opt_CXReps, + opt_IV, + opt_WordSize, + opt_UseSeed, + opt_UseSigSeed, + opt_SeedFile, + opt_InputOffset, + opt_OutputOffset, + opt_MonteCarlo, + opt_CmdLine +}; + +static secuCommandFlag bltest_commands[] = +{ + { /* cmd_Decrypt */ 'D', PR_FALSE, 0, PR_FALSE }, + { /* cmd_Encrypt */ 'E', PR_FALSE, 0, PR_FALSE }, + { /* cmd_FIPS */ 'F', PR_FALSE, 0, PR_FALSE }, + { /* cmd_Hash */ 'H', PR_FALSE, 0, PR_FALSE }, + { /* cmd_Nonce */ 'N', PR_FALSE, 0, PR_FALSE }, + { /* cmd_Dump */ 'P', PR_FALSE, 0, PR_FALSE }, + { /* cmd_Sign */ 'S', PR_FALSE, 0, PR_FALSE }, + { /* cmd_SelfTest */ 'T', PR_FALSE, 0, PR_FALSE }, + { /* cmd_Verify */ 'V', PR_FALSE, 0, PR_FALSE } +}; + +static secuCommandFlag bltest_options[] = +{ + { /* opt_B64 */ 'a', PR_FALSE, 0, PR_FALSE }, + { /* opt_BufSize */ 'b', PR_TRUE, 0, PR_FALSE }, + { /* opt_Restart */ 'c', PR_FALSE, 0, PR_FALSE }, + { /* opt_SelfTestDir */ 'd', PR_TRUE, 0, PR_FALSE }, + { /* opt_Exponent */ 'e', PR_TRUE, 0, PR_FALSE }, + { /* opt_SigFile */ 'f', PR_TRUE, 0, PR_FALSE }, + { /* opt_KeySize */ 'g', PR_TRUE, 0, PR_FALSE }, + { /* opt_Hex */ 'h', PR_FALSE, 0, PR_FALSE }, + { /* opt_Input */ 'i', PR_TRUE, 0, PR_FALSE }, + { /* opt_PQGFile */ 'j', PR_TRUE, 0, PR_FALSE }, + { /* opt_Key */ 'k', PR_TRUE, 0, PR_FALSE }, + { /* opt_HexWSpc */ 'l', PR_FALSE, 0, PR_FALSE }, + { /* opt_Mode */ 'm', PR_TRUE, 0, PR_FALSE }, + { /* opt_Output */ 'o', PR_TRUE, 0, PR_FALSE }, + { /* opt_Repetitions */ 'p', PR_TRUE, 0, PR_FALSE }, + { /* opt_ZeroBuf */ 'q', PR_FALSE, 0, PR_FALSE }, + { /* opt_Rounds */ 'r', PR_TRUE, 0, PR_FALSE }, + { /* opt_Seed */ 's', PR_TRUE, 0, PR_FALSE }, + { /* opt_SigSeedFile */ 't', PR_TRUE, 0, PR_FALSE }, + { /* opt_CXReps */ 'u', PR_TRUE, 0, PR_FALSE }, + { /* opt_IV */ 'v', PR_TRUE, 0, PR_FALSE }, + { /* opt_WordSize */ 'w', PR_TRUE, 0, PR_FALSE }, + { /* opt_UseSeed */ 'x', PR_FALSE, 0, PR_FALSE }, + { /* opt_UseSigSeed */ 'y', PR_FALSE, 0, PR_FALSE }, + { /* opt_SeedFile */ 'z', PR_FALSE, 0, PR_FALSE }, + { /* opt_InputOffset */ '1', PR_TRUE, 0, PR_FALSE }, + { /* opt_OutputOffset */ '2', PR_TRUE, 0, PR_FALSE }, + { /* opt_MonteCarlo */ '3', PR_FALSE, 0, PR_FALSE }, + { /* opt_CmdLine */ '-', PR_FALSE, 0, PR_FALSE } +}; + +int main(int argc, char **argv) +{ + char *infileName, *outfileName, *keyfileName, *ivfileName; + SECStatus rv; + + bltestCipherInfo cipherInfo; + bltestParams *params; + PRFileDesc *file, *infile, *outfile; + char *instr = NULL; + PRArenaPool *arena; + bltestIOMode ioMode; + int keysize, bufsize, exponent; + int i, commandsEntered; + int inoff, outoff; + + secuCommand bltest; + bltest.numCommands = sizeof(bltest_commands) / sizeof(secuCommandFlag); + bltest.numOptions = sizeof(bltest_options) / sizeof(secuCommandFlag); + bltest.commands = bltest_commands; + bltest.options = bltest_options; + + progName = strrchr(argv[0], '/'); + if (!progName) + progName = strrchr(argv[0], '\\'); + progName = progName ? progName+1 : argv[0]; + + rv = RNG_RNGInit(); + if (rv != SECSuccess) { + SECU_PrintPRandOSError(progName); + return -1; + } + RNG_SystemInfoForRNG(); + + rv = SECU_ParseCommandLine(argc, argv, progName, &bltest); + + PORT_Memset(&cipherInfo, 0, sizeof(cipherInfo)); + arena = PORT_NewArena(BLTEST_DEFAULT_CHUNKSIZE); + cipherInfo.arena = arena; + params = &cipherInfo.params; + /* set some defaults */ + infileName = outfileName = keyfileName = ivfileName = NULL; + + /* Check the number of commands entered on the command line. */ + commandsEntered = 0; + for (i=0; i<bltest.numCommands; i++) + if (bltest.commands[i].activated) + commandsEntered++; + + if (commandsEntered > 1 && + !(commandsEntered == 2 && bltest.commands[cmd_SelfTest].activated)) { + fprintf(stderr, "%s: one command at a time!\n", progName); + Usage(); + } + if (commandsEntered == 0) { + fprintf(stderr, "%s: you must enter a command!\n", progName); + Usage(); + } + + if (bltest.commands[cmd_Sign].activated) + bltest.commands[cmd_Encrypt].activated = PR_TRUE; + if (bltest.commands[cmd_Verify].activated) + bltest.commands[cmd_Decrypt].activated = PR_TRUE; + if (bltest.commands[cmd_Hash].activated) + bltest.commands[cmd_Encrypt].activated = PR_TRUE; + + inoff = outoff = 0; + if (bltest.options[opt_InputOffset].activated) + inoff = PORT_Atoi(bltest.options[opt_InputOffset].arg); + if (bltest.options[opt_OutputOffset].activated) + outoff = PORT_Atoi(bltest.options[opt_OutputOffset].arg); + + testdir = (bltest.options[opt_SelfTestDir].activated) ? + strdup(bltest.options[opt_SelfTestDir].arg) : "."; + + /* + * Handle three simple cases first + */ + + /* Do BLAPI self-test */ + if (bltest.commands[cmd_SelfTest].activated) { + PRBool encrypt = PR_TRUE, decrypt = PR_TRUE; + /* user may specified a set of ciphers to test. parse them. */ + bltestCipherMode modesToTest[NUMMODES]; + int numModesToTest = 0; + char *tok, *str; + str = bltest.options[opt_Mode].arg; + while (str) { + tok = strchr(str, ','); + if (tok) *tok = '\0'; + modesToTest[numModesToTest++] = get_mode(str); + if (tok) { + *tok = ','; + str = tok + 1; + } else { + break; + } + } + if (bltest.commands[cmd_Decrypt].activated && + !bltest.commands[cmd_Encrypt].activated) + encrypt = PR_FALSE; + if (bltest.commands[cmd_Encrypt].activated && + !bltest.commands[cmd_Decrypt].activated) + decrypt = PR_FALSE; + return blapi_selftest(modesToTest, numModesToTest, inoff, outoff, + encrypt, decrypt); + } + + /* Do FIPS self-test */ + if (bltest.commands[cmd_FIPS].activated) { + CK_RV ckrv = pk11_fipsPowerUpSelfTest(); + fprintf(stdout, "CK_RV: %ld.\n", ckrv); + return 0; + } + + /* + * Check command line arguments for Encrypt/Decrypt/Hash/Sign/Verify + */ + + if ((bltest.commands[cmd_Decrypt].activated || + bltest.commands[cmd_Verify].activated) && + bltest.options[opt_BufSize].activated) { + fprintf(stderr, "%s: cannot use a nonce as input to decrypt/verify.\n", + progName); + Usage(); + } + + if (bltest.options[opt_Mode].activated) { + cipherInfo.mode = get_mode(bltest.options[opt_Mode].arg); + if (cipherInfo.mode == bltestINVALID) { + fprintf(stderr, "%s: Invalid mode \"%s\"\n", progName, + bltest.options[opt_Mode].arg); + Usage(); + } + } else { + fprintf(stderr, "%s: You must specify a cipher mode with -m.\n", + progName); + Usage(); + } + + if (bltest.options[opt_Repetitions].activated) { + cipherInfo.repetitions = PORT_Atoi(bltest.options[opt_Repetitions].arg); + } else { + cipherInfo.repetitions = 0; + } + + + if (bltest.options[opt_CXReps].activated) { + cipherInfo.cxreps = PORT_Atoi(bltest.options[opt_CXReps].arg); + } else { + cipherInfo.cxreps = 0; + } + + /* Dump a file (rsakey, dsakey, etc.) */ + if (bltest.commands[cmd_Dump].activated) { + return dump_file(cipherInfo.mode, bltest.options[opt_Input].arg); + } + + /* default input mode is binary */ + ioMode = (bltest.options[opt_B64].activated) ? bltestBase64Encoded : + (bltest.options[opt_Hex].activated) ? bltestHexStream : + (bltest.options[opt_HexWSpc].activated) ? bltestHexSpaceDelim : + bltestBinary; + + if (bltest.options[opt_KeySize].activated) + keysize = PORT_Atoi(bltest.options[opt_KeySize].arg); + else + keysize = 0; + + if (bltest.options[opt_Exponent].activated) + exponent = PORT_Atoi(bltest.options[opt_Exponent].arg); + else + exponent = 65537; + + /* Set up an encryption key. */ + keysize = 0; + file = NULL; + if (is_symmkeyCipher(cipherInfo.mode)) { + char *keystr = NULL; /* if key is on command line */ + if (bltest.options[opt_Key].activated) { + if (bltest.options[opt_CmdLine].activated) { + keystr = bltest.options[opt_Key].arg; + } else { + file = PR_Open(bltest.options[opt_Key].arg, PR_RDONLY, 00660); + } + } else { + if (bltest.options[opt_KeySize].activated) + keysize = PORT_Atoi(bltest.options[opt_KeySize].arg); + else + keysize = 8; /* use 64-bit default (DES) */ + /* save the random key for reference */ + file = PR_Open("tmp.key", PR_WRONLY|PR_CREATE_FILE, 00660); + } + params->key.mode = ioMode; + setupIO(cipherInfo.arena, ¶ms->key, file, keystr, keysize); + if (file) + PR_Close(file); + } else if (is_pubkeyCipher(cipherInfo.mode)) { + if (bltest.options[opt_Key].activated) { + file = PR_Open(bltest.options[opt_Key].arg, PR_RDONLY, 00660); + } else { + if (bltest.options[opt_KeySize].activated) + keysize = PORT_Atoi(bltest.options[opt_KeySize].arg); + else + keysize = 64; /* use 512-bit default */ + file = PR_Open("tmp.key", PR_WRONLY|PR_CREATE_FILE, 00660); + } + params->key.mode = bltestBase64Encoded; + pubkeyInitKey(&cipherInfo, file, keysize, exponent); + PR_Close(file); + } + + /* set up an initialization vector. */ + if (cipher_requires_IV(cipherInfo.mode)) { + char *ivstr = NULL; + bltestSymmKeyParams *skp; + file = NULL; + if (cipherInfo.mode == bltestRC5_CBC) + skp = (bltestSymmKeyParams *)¶ms->rc5; + else + skp = ¶ms->sk; + if (bltest.options[opt_IV].activated) { + if (bltest.options[opt_CmdLine].activated) { + ivstr = bltest.options[opt_IV].arg; + } else { + file = PR_Open(bltest.options[opt_IV].arg, PR_RDONLY, 00660); + } + } else { + /* save the random iv for reference */ + file = PR_Open("tmp.iv", PR_WRONLY|PR_CREATE_FILE, 00660); + } + memset(&skp->iv, 0, sizeof skp->iv); + skp->iv.mode = ioMode; + setupIO(cipherInfo.arena, &skp->iv, file, ivstr, keysize); + if (file) + PR_Close(file); + } + + if (bltest.commands[cmd_Verify].activated) { + if (!bltest.options[opt_SigFile].activated) { + fprintf(stderr, "%s: You must specify a signature file with -f.\n", + progName); + exit(-1); + } + file = PR_Open(bltest.options[opt_SigFile].arg, PR_RDONLY, 00660); + memset(&cipherInfo.params.dsa.sig, 0, sizeof(bltestIO)); + cipherInfo.params.dsa.sig.mode = ioMode; + setupIO(cipherInfo.arena, &cipherInfo.params.dsa.sig, file, NULL, 0); + } + + if (bltest.options[opt_PQGFile].activated) { + file = PR_Open(bltest.options[opt_PQGFile].arg, PR_RDONLY, 00660); + params->dsa.pqgdata.mode = bltestBase64Encoded; + setupIO(cipherInfo.arena, ¶ms->dsa.pqgdata, file, NULL, 0); + } + + /* Set up the input buffer */ + if (bltest.options[opt_Input].activated) { + if (bltest.options[opt_CmdLine].activated) { + instr = bltest.options[opt_Input].arg; + infile = NULL; + } else { + /* form file name from testdir and input arg. */ + char * filename = bltest.options[opt_Input].arg; + if (bltest.options[opt_SelfTestDir].activated && + testdir && filename && filename[0] != '/') + filename = PR_smprintf("%s/tests/%s/%s", testdir, + mode_strings[cipherInfo.mode], filename); + infile = PR_Open(filename, PR_RDONLY, 00660); + } + } else if (bltest.options[opt_BufSize].activated) { + /* save the random plaintext for reference */ + infile = PR_Open("tmp.in", PR_WRONLY|PR_CREATE_FILE, 00660); + } else { + infile = PR_STDIN; + } + if (!infile) { + fprintf(stderr, "%s: Failed to open input file.\n", progName); + exit(-1); + } + cipherInfo.input.mode = ioMode; + + /* Set up the output stream */ + if (bltest.options[opt_Output].activated) { + /* form file name from testdir and input arg. */ + char * filename = bltest.options[opt_Output].arg; + if (bltest.options[opt_SelfTestDir].activated && + testdir && filename && filename[0] != '/') + filename = PR_smprintf("%s/tests/%s/%s", testdir, + mode_strings[cipherInfo.mode], filename); + outfile = PR_Open(filename, PR_WRONLY|PR_CREATE_FILE, 00660); + } else { + outfile = PR_STDOUT; + } + if (!outfile) { + fprintf(stderr, "%s: Failed to open output file.\n", progName); + exit(-1); + } + cipherInfo.output.mode = ioMode; + if (bltest.options[opt_SelfTestDir].activated && ioMode == bltestBinary) + cipherInfo.output.mode = bltestBase64Encoded; + + if (is_hashCipher(cipherInfo.mode)) + cipherInfo.params.hash.restart = bltest.options[opt_Restart].activated; + + bufsize = 0; + if (bltest.options[opt_BufSize].activated) + bufsize = PORT_Atoi(bltest.options[opt_BufSize].arg); + + /*infile = NULL;*/ + setupIO(cipherInfo.arena, &cipherInfo.input, infile, instr, bufsize); + misalignBuffer(cipherInfo.arena, &cipherInfo.input, inoff); + + cipherInit(&cipherInfo, bltest.commands[cmd_Encrypt].activated); + misalignBuffer(cipherInfo.arena, &cipherInfo.output, outoff); + + if (!bltest.commands[cmd_Nonce].activated) { + if (bltest.options[opt_MonteCarlo].activated) { + int mciter; + for (mciter=0; mciter<10000; mciter++) { + cipherDoOp(&cipherInfo); + memcpy(cipherInfo.input.buf.data, + cipherInfo.output.buf.data, + cipherInfo.input.buf.len); + } + } else { + cipherDoOp(&cipherInfo); + } + cipherFinish(&cipherInfo); + finishIO(&cipherInfo.output, outfile); + } + + if (cipherInfo.repetitions > 0 || cipherInfo.cxreps > 0) + dump_performance_info(&cipherInfo, + bltest.commands[cmd_Encrypt].activated, + (cipherInfo.repetitions == 0)); + + if (infile && infile != PR_STDIN) + PR_Close(infile); + if (outfile && outfile != PR_STDOUT) + PR_Close(outfile); + PORT_FreeArena(cipherInfo.arena, PR_TRUE); + + /*NSS_Shutdown();*/ + + return SECSuccess; +} diff --git a/security/nss/cmd/bltest/manifest.mn b/security/nss/cmd/bltest/manifest.mn new file mode 100644 index 000000000..2bbe10999 --- /dev/null +++ b/security/nss/cmd/bltest/manifest.mn @@ -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. +# +CORE_DEPTH = ../../.. + +MODULE = nss + +REQUIRES = seccmd dbm + +INCLUDES += -I$(CORE_DEPTH)/nss/lib/softoken + +PROGRAM = bltest + + USE_STATIC_LIBS = 1 + +EXPORTS = \ + $(NULL) + +PRIVATE_EXPORTS = \ + $(NULL) + +CSRCS = \ + blapitest.c \ + $(NULL) + diff --git a/security/nss/cmd/bltest/tests/README b/security/nss/cmd/bltest/tests/README new file mode 100644 index 000000000..9982a2f15 --- /dev/null +++ b/security/nss/cmd/bltest/tests/README @@ -0,0 +1,49 @@ +This directory contains a set of tests for each cipher supported by +BLAPI. Each subdirectory contains known plaintext and ciphertext pairs +(and keys and/or iv's if needed). The tests can be run as a full set +with: + bltest -T +or as subsets, for example: + bltest -T -m des_ecb,md2,rsa + +In each subdirectory, the plaintext, key, and iv are ascii, and treated +as such. The ciphertext is base64-encoded to avoid the hassle of binary +files. + +To add a test, incremement the value in the numtests file. Create a +plaintext, key, and iv file, such that the name of the file is +incrememted one from the last set of tests. For example, if you are +adding the second test, put your data in files named plaintext1, key1, +and iv1 (ignoring key and iv if they are not needed, of course). Make +sure your key and iv are the correct number of bytes for your cipher (a +trailing \n is okay, but any other trailing bytes will be used!). Once +you have your input data, create output data by running bltest on a +trusted implementation. For example, for a new DES ECB test, run + bltest -E -m des_ecb -i plaintext1 -k key1 -o ciphertext1 -a in the +tests/des_ecb directory. Then run + bltest -T des_ecb from the cmd/bltest directory in the tree of the +implementation you want to test. + +Note that the -a option above is important, it tells bltest to expect +the input to be straight ASCII, and not base64 encoded binary! + +Special cases: + +RC5: +RC5 can take additional parameters, the number of rounds to perform and +the wordsize to use. The number of rounds is between is between 0 and +255, and the wordsize is either is either 16, 32, or 64 bits (at this +time only 32-bit is supported). These parameters are specified in a +paramsN file, where N is an index as above. The format of the file is +"rounds=R\nwordsize=W\n". + +public key modes (RSA and DSA): +Asymmetric key ciphers use keys with special properties, so creating a +key file with "Mozilla!" in it will not get you very far! To create a +public key, run bltest with the plaintext you want to encrypt, using a +trusted implementation. bltest will generate a key and store it in +"tmp.key", rename that file to keyN. For example: + bltest -E -m rsa -i plaintext0 -o ciphertext0 -e 65537 -g 32 -a + mv tmp.key key0 + +[note: specifying a keysize (-g) when using RSA is important!] diff --git a/security/nss/cmd/bltest/tests/aes_cbc/ciphertext0 b/security/nss/cmd/bltest/tests/aes_cbc/ciphertext0 new file mode 100644 index 000000000..040a397d7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/aes_cbc/ciphertext0 @@ -0,0 +1 @@ +oJLgOzZ1GiWt3DGo2sPKaA==
diff --git a/security/nss/cmd/bltest/tests/aes_cbc/iv0 b/security/nss/cmd/bltest/tests/aes_cbc/iv0 new file mode 100644 index 000000000..4e65bc034 --- /dev/null +++ b/security/nss/cmd/bltest/tests/aes_cbc/iv0 @@ -0,0 +1 @@ +qwertyuiopasdfgh diff --git a/security/nss/cmd/bltest/tests/aes_cbc/key0 b/security/nss/cmd/bltest/tests/aes_cbc/key0 new file mode 100644 index 000000000..13911cc29 --- /dev/null +++ b/security/nss/cmd/bltest/tests/aes_cbc/key0 @@ -0,0 +1 @@ +fedcba9876543210 diff --git a/security/nss/cmd/bltest/tests/aes_cbc/numtests b/security/nss/cmd/bltest/tests/aes_cbc/numtests new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/aes_cbc/numtests @@ -0,0 +1 @@ +1 diff --git a/security/nss/cmd/bltest/tests/aes_cbc/plaintext0 b/security/nss/cmd/bltest/tests/aes_cbc/plaintext0 new file mode 100644 index 000000000..8d6a8d555 --- /dev/null +++ b/security/nss/cmd/bltest/tests/aes_cbc/plaintext0 @@ -0,0 +1 @@ +0123456789abcdef diff --git a/security/nss/cmd/bltest/tests/aes_ecb/ciphertext0 b/security/nss/cmd/bltest/tests/aes_ecb/ciphertext0 new file mode 100644 index 000000000..d6818c1d0 --- /dev/null +++ b/security/nss/cmd/bltest/tests/aes_ecb/ciphertext0 @@ -0,0 +1 @@ +PVuaCIiaKQhblgFCbVMTTg==
diff --git a/security/nss/cmd/bltest/tests/aes_ecb/key0 b/security/nss/cmd/bltest/tests/aes_ecb/key0 new file mode 100644 index 000000000..13911cc29 --- /dev/null +++ b/security/nss/cmd/bltest/tests/aes_ecb/key0 @@ -0,0 +1 @@ +fedcba9876543210 diff --git a/security/nss/cmd/bltest/tests/aes_ecb/numtests b/security/nss/cmd/bltest/tests/aes_ecb/numtests new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/aes_ecb/numtests @@ -0,0 +1 @@ +1 diff --git a/security/nss/cmd/bltest/tests/aes_ecb/plaintext0 b/security/nss/cmd/bltest/tests/aes_ecb/plaintext0 new file mode 100644 index 000000000..8d6a8d555 --- /dev/null +++ b/security/nss/cmd/bltest/tests/aes_ecb/plaintext0 @@ -0,0 +1 @@ +0123456789abcdef diff --git a/security/nss/cmd/bltest/tests/des3_cbc/ciphertext0 b/security/nss/cmd/bltest/tests/des3_cbc/ciphertext0 new file mode 100644 index 000000000..61dae3192 --- /dev/null +++ b/security/nss/cmd/bltest/tests/des3_cbc/ciphertext0 @@ -0,0 +1 @@ +KV3MDNGKWOc= diff --git a/security/nss/cmd/bltest/tests/des3_cbc/iv0 b/security/nss/cmd/bltest/tests/des3_cbc/iv0 new file mode 100644 index 000000000..97b5955f7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/des3_cbc/iv0 @@ -0,0 +1 @@ +12345678 diff --git a/security/nss/cmd/bltest/tests/des3_cbc/key0 b/security/nss/cmd/bltest/tests/des3_cbc/key0 new file mode 100644 index 000000000..588efd111 --- /dev/null +++ b/security/nss/cmd/bltest/tests/des3_cbc/key0 @@ -0,0 +1 @@ +abcdefghijklmnopqrstuvwx diff --git a/security/nss/cmd/bltest/tests/des3_cbc/numtests b/security/nss/cmd/bltest/tests/des3_cbc/numtests new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/des3_cbc/numtests @@ -0,0 +1 @@ +1 diff --git a/security/nss/cmd/bltest/tests/des3_cbc/plaintext0 b/security/nss/cmd/bltest/tests/des3_cbc/plaintext0 new file mode 100644 index 000000000..5513e438c --- /dev/null +++ b/security/nss/cmd/bltest/tests/des3_cbc/plaintext0 @@ -0,0 +1 @@ +Mozilla! diff --git a/security/nss/cmd/bltest/tests/des3_ecb/ciphertext0 b/security/nss/cmd/bltest/tests/des3_ecb/ciphertext0 new file mode 100644 index 000000000..76dc820d3 --- /dev/null +++ b/security/nss/cmd/bltest/tests/des3_ecb/ciphertext0 @@ -0,0 +1 @@ +RgckVNh4QcM= diff --git a/security/nss/cmd/bltest/tests/des3_ecb/key0 b/security/nss/cmd/bltest/tests/des3_ecb/key0 new file mode 100644 index 000000000..588efd111 --- /dev/null +++ b/security/nss/cmd/bltest/tests/des3_ecb/key0 @@ -0,0 +1 @@ +abcdefghijklmnopqrstuvwx diff --git a/security/nss/cmd/bltest/tests/des3_ecb/numtests b/security/nss/cmd/bltest/tests/des3_ecb/numtests new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/des3_ecb/numtests @@ -0,0 +1 @@ +1 diff --git a/security/nss/cmd/bltest/tests/des3_ecb/plaintext0 b/security/nss/cmd/bltest/tests/des3_ecb/plaintext0 new file mode 100644 index 000000000..5513e438c --- /dev/null +++ b/security/nss/cmd/bltest/tests/des3_ecb/plaintext0 @@ -0,0 +1 @@ +Mozilla! diff --git a/security/nss/cmd/bltest/tests/des_cbc/ciphertext0 b/security/nss/cmd/bltest/tests/des_cbc/ciphertext0 new file mode 100644 index 000000000..67d2ad1aa --- /dev/null +++ b/security/nss/cmd/bltest/tests/des_cbc/ciphertext0 @@ -0,0 +1 @@ +Perdg9FMYQ4= diff --git a/security/nss/cmd/bltest/tests/des_cbc/iv0 b/security/nss/cmd/bltest/tests/des_cbc/iv0 new file mode 100644 index 000000000..97b5955f7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/des_cbc/iv0 @@ -0,0 +1 @@ +12345678 diff --git a/security/nss/cmd/bltest/tests/des_cbc/key0 b/security/nss/cmd/bltest/tests/des_cbc/key0 new file mode 100644 index 000000000..65513c116 --- /dev/null +++ b/security/nss/cmd/bltest/tests/des_cbc/key0 @@ -0,0 +1 @@ +zyxwvuts diff --git a/security/nss/cmd/bltest/tests/des_cbc/numtests b/security/nss/cmd/bltest/tests/des_cbc/numtests new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/des_cbc/numtests @@ -0,0 +1 @@ +1 diff --git a/security/nss/cmd/bltest/tests/des_cbc/plaintext0 b/security/nss/cmd/bltest/tests/des_cbc/plaintext0 new file mode 100644 index 000000000..5513e438c --- /dev/null +++ b/security/nss/cmd/bltest/tests/des_cbc/plaintext0 @@ -0,0 +1 @@ +Mozilla! diff --git a/security/nss/cmd/bltest/tests/des_ecb/ciphertext0 b/security/nss/cmd/bltest/tests/des_ecb/ciphertext0 new file mode 100644 index 000000000..8be22fa5c --- /dev/null +++ b/security/nss/cmd/bltest/tests/des_ecb/ciphertext0 @@ -0,0 +1 @@ +3bNoWzzNiFc= diff --git a/security/nss/cmd/bltest/tests/des_ecb/key0 b/security/nss/cmd/bltest/tests/des_ecb/key0 new file mode 100644 index 000000000..65513c116 --- /dev/null +++ b/security/nss/cmd/bltest/tests/des_ecb/key0 @@ -0,0 +1 @@ +zyxwvuts diff --git a/security/nss/cmd/bltest/tests/des_ecb/numtests b/security/nss/cmd/bltest/tests/des_ecb/numtests new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/des_ecb/numtests @@ -0,0 +1 @@ +1 diff --git a/security/nss/cmd/bltest/tests/des_ecb/plaintext0 b/security/nss/cmd/bltest/tests/des_ecb/plaintext0 new file mode 100644 index 000000000..5513e438c --- /dev/null +++ b/security/nss/cmd/bltest/tests/des_ecb/plaintext0 @@ -0,0 +1 @@ +Mozilla! diff --git a/security/nss/cmd/bltest/tests/dsa/ciphertext0 b/security/nss/cmd/bltest/tests/dsa/ciphertext0 new file mode 100644 index 000000000..8e7150562 --- /dev/null +++ b/security/nss/cmd/bltest/tests/dsa/ciphertext0 @@ -0,0 +1 @@ +fB0bnKWvjT6X5NIkZ5l/Y/DXZ6QNI6j0iPhR/ZERkfj67xRnTWY1cg== diff --git a/security/nss/cmd/bltest/tests/dsa/key0 b/security/nss/cmd/bltest/tests/dsa/key0 new file mode 100644 index 000000000..e582eeb04 --- /dev/null +++ b/security/nss/cmd/bltest/tests/dsa/key0 @@ -0,0 +1,6 @@ +AAAAQI3ypJRJInaqPSV1m7BoacvqwNg6+40M98u4Mk8NeILl0HYvxbchDq/C6a2s
+Mqt6rElpPfv4NyTC7Ac27jHIApEAAAAUx3MhjHN+yO6ZO08t7TD0jtrOkV8AAABA
+Ym0CeDnqChNBMWOlW0y1ACmdVSKVbO/LO/8Q85nOLC5xy53l+iS6v1jlt5Uhklyc
+xC6fb0ZLCIzFcq9T5teIAgAAAEAZExhx11sWEqgZ8p140bDXNG96p3u2KoWb/WxW
+ddqdIS06Nu8Wcu9mC4x8JVzA7HSFj7oz9EwGaZYwp2sDDuMzAAAAFCBwsyI9ujcv
+3hwP/HsuO0mLJgYU
diff --git a/security/nss/cmd/bltest/tests/dsa/keyseed0 b/security/nss/cmd/bltest/tests/dsa/keyseed0 new file mode 100644 index 000000000..6eea359db --- /dev/null +++ b/security/nss/cmd/bltest/tests/dsa/keyseed0 @@ -0,0 +1 @@ +AAAAAAAAAAAAAAAAAAAAAAAAAAA=
diff --git a/security/nss/cmd/bltest/tests/dsa/numtests b/security/nss/cmd/bltest/tests/dsa/numtests new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/dsa/numtests @@ -0,0 +1 @@ +1 diff --git a/security/nss/cmd/bltest/tests/dsa/plaintext0 b/security/nss/cmd/bltest/tests/dsa/plaintext0 new file mode 100644 index 000000000..48fbdb6fd --- /dev/null +++ b/security/nss/cmd/bltest/tests/dsa/plaintext0 @@ -0,0 +1 @@ +qZk+NkcGgWq6PiVxeFDCbJzQ2J0=
diff --git a/security/nss/cmd/bltest/tests/dsa/pqg0 b/security/nss/cmd/bltest/tests/dsa/pqg0 new file mode 100644 index 000000000..f16326ccc --- /dev/null +++ b/security/nss/cmd/bltest/tests/dsa/pqg0 @@ -0,0 +1,4 @@ +AAAAQI3ypJRJInaqPSV1m7BoacvqwNg6+40M98u4Mk8NeILl0HYvxbchDq/C6a2s
+Mqt6rElpPfv4NyTC7Ac27jHIApEAAAAUx3MhjHN+yO6ZO08t7TD0jtrOkV8AAABA
+Ym0CeDnqChNBMWOlW0y1ACmdVSKVbO/LO/8Q85nOLC5xy53l+iS6v1jlt5Uhklyc
+xC6fb0ZLCIzFcq9T5teIAg==
diff --git a/security/nss/cmd/bltest/tests/dsa/sigseed0 b/security/nss/cmd/bltest/tests/dsa/sigseed0 new file mode 100644 index 000000000..05d7fd2d6 --- /dev/null +++ b/security/nss/cmd/bltest/tests/dsa/sigseed0 @@ -0,0 +1 @@ +aHpm2QZI+ZOGfhIfTd+d2wEgVYQ=
diff --git a/security/nss/cmd/bltest/tests/md2/ciphertext0 b/security/nss/cmd/bltest/tests/md2/ciphertext0 new file mode 100644 index 000000000..22e1fc496 --- /dev/null +++ b/security/nss/cmd/bltest/tests/md2/ciphertext0 @@ -0,0 +1 @@ +CS/UNcrWhB5Knt7Gf8Tz3Q== diff --git a/security/nss/cmd/bltest/tests/md2/numtests b/security/nss/cmd/bltest/tests/md2/numtests new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/md2/numtests @@ -0,0 +1 @@ +1 diff --git a/security/nss/cmd/bltest/tests/md2/plaintext0 b/security/nss/cmd/bltest/tests/md2/plaintext0 new file mode 100644 index 000000000..dce2994ba --- /dev/null +++ b/security/nss/cmd/bltest/tests/md2/plaintext0 @@ -0,0 +1 @@ +16-bytes to MD2. diff --git a/security/nss/cmd/bltest/tests/md5/ciphertext0 b/security/nss/cmd/bltest/tests/md5/ciphertext0 new file mode 100644 index 000000000..ea11ee523 --- /dev/null +++ b/security/nss/cmd/bltest/tests/md5/ciphertext0 @@ -0,0 +1 @@ +XN8lnQuWAiMqmSGfvd8Hdw== diff --git a/security/nss/cmd/bltest/tests/md5/numtests b/security/nss/cmd/bltest/tests/md5/numtests new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/md5/numtests @@ -0,0 +1 @@ +1 diff --git a/security/nss/cmd/bltest/tests/md5/plaintext0 b/security/nss/cmd/bltest/tests/md5/plaintext0 new file mode 100644 index 000000000..5ae3875e2 --- /dev/null +++ b/security/nss/cmd/bltest/tests/md5/plaintext0 @@ -0,0 +1 @@ +63-byte input to MD5 can be a bit tricky, but no problems here. diff --git a/security/nss/cmd/bltest/tests/rc2_cbc/ciphertext0 b/security/nss/cmd/bltest/tests/rc2_cbc/ciphertext0 new file mode 100644 index 000000000..d964ef864 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc2_cbc/ciphertext0 @@ -0,0 +1 @@ +3ki6eVsWpY8= diff --git a/security/nss/cmd/bltest/tests/rc2_cbc/iv0 b/security/nss/cmd/bltest/tests/rc2_cbc/iv0 new file mode 100644 index 000000000..97b5955f7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc2_cbc/iv0 @@ -0,0 +1 @@ +12345678 diff --git a/security/nss/cmd/bltest/tests/rc2_cbc/key0 b/security/nss/cmd/bltest/tests/rc2_cbc/key0 new file mode 100644 index 000000000..65513c116 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc2_cbc/key0 @@ -0,0 +1 @@ +zyxwvuts diff --git a/security/nss/cmd/bltest/tests/rc2_cbc/numtests b/security/nss/cmd/bltest/tests/rc2_cbc/numtests new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc2_cbc/numtests @@ -0,0 +1 @@ +1 diff --git a/security/nss/cmd/bltest/tests/rc2_cbc/plaintext0 b/security/nss/cmd/bltest/tests/rc2_cbc/plaintext0 new file mode 100644 index 000000000..5513e438c --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc2_cbc/plaintext0 @@ -0,0 +1 @@ +Mozilla! diff --git a/security/nss/cmd/bltest/tests/rc2_ecb/ciphertext0 b/security/nss/cmd/bltest/tests/rc2_ecb/ciphertext0 new file mode 100644 index 000000000..337d30765 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc2_ecb/ciphertext0 @@ -0,0 +1 @@ +WT+tc4fANhQ= diff --git a/security/nss/cmd/bltest/tests/rc2_ecb/key0 b/security/nss/cmd/bltest/tests/rc2_ecb/key0 new file mode 100644 index 000000000..65513c116 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc2_ecb/key0 @@ -0,0 +1 @@ +zyxwvuts diff --git a/security/nss/cmd/bltest/tests/rc2_ecb/numtests b/security/nss/cmd/bltest/tests/rc2_ecb/numtests new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc2_ecb/numtests @@ -0,0 +1 @@ +1 diff --git a/security/nss/cmd/bltest/tests/rc2_ecb/plaintext0 b/security/nss/cmd/bltest/tests/rc2_ecb/plaintext0 new file mode 100644 index 000000000..5513e438c --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc2_ecb/plaintext0 @@ -0,0 +1 @@ +Mozilla! diff --git a/security/nss/cmd/bltest/tests/rc4/ciphertext0 b/security/nss/cmd/bltest/tests/rc4/ciphertext0 new file mode 100644 index 000000000..004f13472 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc4/ciphertext0 @@ -0,0 +1 @@ +34sTZJtr20k= diff --git a/security/nss/cmd/bltest/tests/rc4/ciphertext1 b/security/nss/cmd/bltest/tests/rc4/ciphertext1 new file mode 100644 index 000000000..6050da4c6 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc4/ciphertext1 @@ -0,0 +1 @@ +34sTZJtr20nGP6VxS3BIBxxIYm6QGIa1rehFHn51z9M= diff --git a/security/nss/cmd/bltest/tests/rc4/key0 b/security/nss/cmd/bltest/tests/rc4/key0 new file mode 100644 index 000000000..65513c116 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc4/key0 @@ -0,0 +1 @@ +zyxwvuts diff --git a/security/nss/cmd/bltest/tests/rc4/key1 b/security/nss/cmd/bltest/tests/rc4/key1 new file mode 100644 index 000000000..65513c116 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc4/key1 @@ -0,0 +1 @@ +zyxwvuts diff --git a/security/nss/cmd/bltest/tests/rc4/numtests b/security/nss/cmd/bltest/tests/rc4/numtests new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc4/numtests @@ -0,0 +1 @@ +2 diff --git a/security/nss/cmd/bltest/tests/rc4/plaintext0 b/security/nss/cmd/bltest/tests/rc4/plaintext0 new file mode 100644 index 000000000..5513e438c --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc4/plaintext0 @@ -0,0 +1 @@ +Mozilla! diff --git a/security/nss/cmd/bltest/tests/rc4/plaintext1 b/security/nss/cmd/bltest/tests/rc4/plaintext1 new file mode 100644 index 000000000..d41abc7b8 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc4/plaintext1 @@ -0,0 +1 @@ +Mozilla!Mozilla!Mozilla!Mozilla! diff --git a/security/nss/cmd/bltest/tests/rc5_cbc/ciphertext0 b/security/nss/cmd/bltest/tests/rc5_cbc/ciphertext0 new file mode 100644 index 000000000..544713b33 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc5_cbc/ciphertext0 @@ -0,0 +1 @@ +qsv4Fn2J6d0= diff --git a/security/nss/cmd/bltest/tests/rc5_cbc/iv0 b/security/nss/cmd/bltest/tests/rc5_cbc/iv0 new file mode 100644 index 000000000..97b5955f7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc5_cbc/iv0 @@ -0,0 +1 @@ +12345678 diff --git a/security/nss/cmd/bltest/tests/rc5_cbc/key0 b/security/nss/cmd/bltest/tests/rc5_cbc/key0 new file mode 100644 index 000000000..65513c116 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc5_cbc/key0 @@ -0,0 +1 @@ +zyxwvuts diff --git a/security/nss/cmd/bltest/tests/rc5_cbc/numtests b/security/nss/cmd/bltest/tests/rc5_cbc/numtests new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc5_cbc/numtests @@ -0,0 +1 @@ +1 diff --git a/security/nss/cmd/bltest/tests/rc5_cbc/params0 b/security/nss/cmd/bltest/tests/rc5_cbc/params0 new file mode 100644 index 000000000..d68e0362d --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc5_cbc/params0 @@ -0,0 +1,2 @@ +rounds=10 +wordsize=4 diff --git a/security/nss/cmd/bltest/tests/rc5_cbc/plaintext0 b/security/nss/cmd/bltest/tests/rc5_cbc/plaintext0 new file mode 100644 index 000000000..5513e438c --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc5_cbc/plaintext0 @@ -0,0 +1 @@ +Mozilla! diff --git a/security/nss/cmd/bltest/tests/rc5_ecb/ciphertext0 b/security/nss/cmd/bltest/tests/rc5_ecb/ciphertext0 new file mode 100644 index 000000000..133777dd0 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc5_ecb/ciphertext0 @@ -0,0 +1 @@ +4ZKK/1v5Ohc= diff --git a/security/nss/cmd/bltest/tests/rc5_ecb/key0 b/security/nss/cmd/bltest/tests/rc5_ecb/key0 new file mode 100644 index 000000000..65513c116 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc5_ecb/key0 @@ -0,0 +1 @@ +zyxwvuts diff --git a/security/nss/cmd/bltest/tests/rc5_ecb/numtests b/security/nss/cmd/bltest/tests/rc5_ecb/numtests new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc5_ecb/numtests @@ -0,0 +1 @@ +1 diff --git a/security/nss/cmd/bltest/tests/rc5_ecb/params0 b/security/nss/cmd/bltest/tests/rc5_ecb/params0 new file mode 100644 index 000000000..d68e0362d --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc5_ecb/params0 @@ -0,0 +1,2 @@ +rounds=10 +wordsize=4 diff --git a/security/nss/cmd/bltest/tests/rc5_ecb/plaintext0 b/security/nss/cmd/bltest/tests/rc5_ecb/plaintext0 new file mode 100644 index 000000000..5513e438c --- /dev/null +++ b/security/nss/cmd/bltest/tests/rc5_ecb/plaintext0 @@ -0,0 +1 @@ +Mozilla! diff --git a/security/nss/cmd/bltest/tests/rsa/ciphertext0 b/security/nss/cmd/bltest/tests/rsa/ciphertext0 new file mode 100644 index 000000000..943ea599a --- /dev/null +++ b/security/nss/cmd/bltest/tests/rsa/ciphertext0 @@ -0,0 +1 @@ +qPVrXv0y3SC5rY44bIi6GE4Aec8uDpHH7/cCg0FU5as= diff --git a/security/nss/cmd/bltest/tests/rsa/key0 b/security/nss/cmd/bltest/tests/rsa/key0 new file mode 100644 index 000000000..1352fe986 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rsa/key0 @@ -0,0 +1,4 @@ +AAAAAAAAACC5lyu2K2ro8YGnvOCKaL1sFX1HEIblIVbuMXsa8oeFSwAAAAERAAAA
+IBXVjKwFG6LvPG4WOIjBBzmxGNpkQwDs3W5qZcXVzqahAAAAEOEOH/WnhZCJyM39
+oNfhf18AAAAQ0xvmxqXXs3L62xxogUl9lQAAABAaeiHgqkvy4wiQtG1Gkv/tAAAA
+EMaw2TNu6SFdKFXAYluQdjEAAAAQi0u+IlgKCt/hatGAsTrfzQ==
diff --git a/security/nss/cmd/bltest/tests/rsa/numtests b/security/nss/cmd/bltest/tests/rsa/numtests new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/rsa/numtests @@ -0,0 +1 @@ +1 diff --git a/security/nss/cmd/bltest/tests/rsa/plaintext0 b/security/nss/cmd/bltest/tests/rsa/plaintext0 new file mode 100644 index 000000000..d915bc88c --- /dev/null +++ b/security/nss/cmd/bltest/tests/rsa/plaintext0 @@ -0,0 +1 @@ +512bitsforRSAPublicKeyEncryption diff --git a/security/nss/cmd/bltest/tests/sha1/ciphertext0 b/security/nss/cmd/bltest/tests/sha1/ciphertext0 new file mode 100644 index 000000000..1fe4bd2bd --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha1/ciphertext0 @@ -0,0 +1 @@ +cDSMAygXMPIJZC5bntZ4ZhecQ9g= diff --git a/security/nss/cmd/bltest/tests/sha1/numtests b/security/nss/cmd/bltest/tests/sha1/numtests new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha1/numtests @@ -0,0 +1 @@ +1 diff --git a/security/nss/cmd/bltest/tests/sha1/plaintext0 b/security/nss/cmd/bltest/tests/sha1/plaintext0 new file mode 100644 index 000000000..863e79c65 --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha1/plaintext0 @@ -0,0 +1 @@ +A cage went in search of a bird. diff --git a/security/nss/cmd/bltest/tests/sha256/ciphertext0 b/security/nss/cmd/bltest/tests/sha256/ciphertext0 new file mode 100644 index 000000000..07e2ff14f --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha256/ciphertext0 @@ -0,0 +1 @@ +ungWv48Bz+pBQUDeXa4iI7ADYaOWF3qctBD/YfIAFa0= diff --git a/security/nss/cmd/bltest/tests/sha256/ciphertext1 b/security/nss/cmd/bltest/tests/sha256/ciphertext1 new file mode 100644 index 000000000..2ab6e1da5 --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha256/ciphertext1 @@ -0,0 +1 @@ +JI1qYdIGOLjlwCaTDD5gOaM85Flk/yFn9uzt1BnbBsE= diff --git a/security/nss/cmd/bltest/tests/sha256/numtests b/security/nss/cmd/bltest/tests/sha256/numtests new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha256/numtests @@ -0,0 +1 @@ +2 diff --git a/security/nss/cmd/bltest/tests/sha256/plaintext0 b/security/nss/cmd/bltest/tests/sha256/plaintext0 new file mode 100644 index 000000000..8baef1b4a --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha256/plaintext0 @@ -0,0 +1 @@ +abc diff --git a/security/nss/cmd/bltest/tests/sha256/plaintext1 b/security/nss/cmd/bltest/tests/sha256/plaintext1 new file mode 100644 index 000000000..afb5dce5d --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha256/plaintext1 @@ -0,0 +1 @@ +abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq diff --git a/security/nss/cmd/bltest/tests/sha384/ciphertext0 b/security/nss/cmd/bltest/tests/sha384/ciphertext0 new file mode 100644 index 000000000..c94f91e22 --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha384/ciphertext0 @@ -0,0 +1 @@ +ywB1P0WjXou1oD1pmsZQBycsMqsO3tFjGotgWkP/W+2AhgcroefMI1i67KE0yCWn diff --git a/security/nss/cmd/bltest/tests/sha384/ciphertext1 b/security/nss/cmd/bltest/tests/sha384/ciphertext1 new file mode 100644 index 000000000..833f06d84 --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha384/ciphertext1 @@ -0,0 +1 @@ +CTMMM/cRR+g9GS/Hgs0bR1MRGxc7OwXSL6CAhuOw9xL8x8caVX4tuWbD6fqRdGA5 diff --git a/security/nss/cmd/bltest/tests/sha384/numtests b/security/nss/cmd/bltest/tests/sha384/numtests new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha384/numtests @@ -0,0 +1 @@ +2 diff --git a/security/nss/cmd/bltest/tests/sha384/plaintext0 b/security/nss/cmd/bltest/tests/sha384/plaintext0 new file mode 100644 index 000000000..8baef1b4a --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha384/plaintext0 @@ -0,0 +1 @@ +abc diff --git a/security/nss/cmd/bltest/tests/sha384/plaintext1 b/security/nss/cmd/bltest/tests/sha384/plaintext1 new file mode 100644 index 000000000..94fcc2b29 --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha384/plaintext1 @@ -0,0 +1 @@ +abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu diff --git a/security/nss/cmd/bltest/tests/sha512/ciphertext0 b/security/nss/cmd/bltest/tests/sha512/ciphertext0 new file mode 100644 index 000000000..8b626e237 --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha512/ciphertext0 @@ -0,0 +1,2 @@ +3a81oZNherrMQXNJriBBMRLm+k6JqX6iCp7u5ktV05ohkpkqJ0/BqDa6PCOj/uu9 +RU1EI2Q86A4qmslPpUyknw== diff --git a/security/nss/cmd/bltest/tests/sha512/ciphertext1 b/security/nss/cmd/bltest/tests/sha512/ciphertext1 new file mode 100644 index 000000000..c02d1752d --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha512/ciphertext1 @@ -0,0 +1,2 @@ +jpWbddrjE9qM9PcoFPwUP493ecbrn3+hcpmurbaIkBhQHSieSQD35DMbmd7EtUM6 +x9Mp7rbdJlReluVbh0vpCQ== diff --git a/security/nss/cmd/bltest/tests/sha512/numtests b/security/nss/cmd/bltest/tests/sha512/numtests new file mode 100644 index 000000000..0cfbf0888 --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha512/numtests @@ -0,0 +1 @@ +2 diff --git a/security/nss/cmd/bltest/tests/sha512/plaintext0 b/security/nss/cmd/bltest/tests/sha512/plaintext0 new file mode 100644 index 000000000..8baef1b4a --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha512/plaintext0 @@ -0,0 +1 @@ +abc diff --git a/security/nss/cmd/bltest/tests/sha512/plaintext1 b/security/nss/cmd/bltest/tests/sha512/plaintext1 new file mode 100644 index 000000000..94fcc2b29 --- /dev/null +++ b/security/nss/cmd/bltest/tests/sha512/plaintext1 @@ -0,0 +1 @@ +abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu diff --git a/security/nss/cmd/btoa/Makefile b/security/nss/cmd/btoa/Makefile new file mode 100644 index 000000000..763faa253 --- /dev/null +++ b/security/nss/cmd/btoa/Makefile @@ -0,0 +1,75 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/btoa/btoa.c b/security/nss/cmd/btoa/btoa.c new file mode 100644 index 000000000..d58805c65 --- /dev/null +++ b/security/nss/cmd/btoa/btoa.c @@ -0,0 +1,196 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "plgetopt.h" +#include "secutil.h" +#include "nssb64.h" +#include <errno.h> + +#if defined(XP_WIN) || (defined(__sun) && !defined(SVR4)) +#if !defined(WIN32) +extern int fread(char *, size_t, size_t, FILE*); +extern int fwrite(char *, size_t, size_t, FILE*); +extern int fprintf(FILE *, char *, ...); +#endif +#endif + +#if defined(WIN32) +#include "fcntl.h" +#include "io.h" +#endif + +static PRInt32 +output_ascii (void *arg, const char *obuf, PRInt32 size) +{ + FILE *outFile = arg; + int nb; + + nb = fwrite(obuf, 1, size, outFile); + if (nb != size) { + PORT_SetError(SEC_ERROR_IO); + return -1; + } + + return nb; +} + +static SECStatus +encode_file(FILE *outFile, FILE *inFile) +{ + NSSBase64Encoder *cx; + int nb; + SECStatus status = SECFailure; + unsigned char ibuf[4096]; + + cx = NSSBase64Encoder_Create(output_ascii, outFile); + if (!cx) { + return -1; + } + + for (;;) { + if (feof(inFile)) break; + nb = fread(ibuf, 1, sizeof(ibuf), inFile); + if (nb != sizeof(ibuf)) { + if (nb == 0) { + if (ferror(inFile)) { + PORT_SetError(SEC_ERROR_IO); + goto loser; + } + /* eof */ + break; + } + } + + status = NSSBase64Encoder_Update(cx, ibuf, nb); + if (status != SECSuccess) goto loser; + } + + status = NSSBase64Encoder_Destroy(cx, PR_FALSE); + if (status != SECSuccess) + return status; + + /* + * Add a trailing CRLF. Note this must be done *after* the call + * to Destroy above (because only then are we sure all data has + * been written out). + */ + fwrite("\r\n", 1, 2, outFile); + return SECSuccess; + + loser: + (void) NSSBase64Encoder_Destroy(cx, PR_TRUE); + return status; +} + +static void Usage(char *progName) +{ + fprintf(stderr, + "Usage: %s [-i input] [-o output]\n", + progName); + fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n", + "-i input"); + fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n", + "-o output"); + exit(-1); +} + +int main(int argc, char **argv) +{ + char *progName; + SECStatus rv; + FILE *inFile, *outFile; + PLOptState *optstate; + PLOptStatus status; + + inFile = 0; + outFile = 0; + progName = strrchr(argv[0], '/'); + if (!progName) + progName = strrchr(argv[0], '\\'); + progName = progName ? progName+1 : argv[0]; + + /* Parse command line arguments */ + optstate = PL_CreateOptState(argc, argv, "i:o:"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + default: + Usage(progName); + break; + + case 'i': + inFile = fopen(optstate->value, "rb"); + if (!inFile) { + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", + progName, optstate->value); + return -1; + } + break; + + case 'o': + outFile = fopen(optstate->value, "w"); + if (!outFile) { + fprintf(stderr, "%s: unable to open \"%s\" for writing\n", + progName, optstate->value); + return -1; + } + break; + } + } + if (status == PL_OPT_BAD) + Usage(progName); + if (!inFile) { +#if defined(WIN32) + /* If we're going to read binary data from stdin, we must put stdin + ** into O_BINARY mode or else incoming \r\n's will become \n's. + */ + + int smrv = _setmode(_fileno(stdin), _O_BINARY); + if (smrv == -1) { + fprintf(stderr, + "%s: Cannot change stdin to binary mode. Use -i option instead.\n", + progName); + return smrv; + } +#endif + inFile = stdin; + } + if (!outFile) + outFile = stdout; + rv = encode_file(outFile, inFile); + if (rv != SECSuccess) { + fprintf(stderr, "%s: lossage: error=%d errno=%d\n", + progName, PORT_GetError(), errno); + return -1; + } + return 0; +} diff --git a/security/nss/cmd/btoa/makefile.win b/security/nss/cmd/btoa/makefile.win new file mode 100644 index 000000000..28d3ee873 --- /dev/null +++ b/security/nss/cmd/btoa/makefile.win @@ -0,0 +1,130 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +VERBOSE = 1 +include <manifest.mn> + +#cannot define PROGRAM in manifest compatibly with NT and UNIX +PROGRAM = btoa +PROGRAM = ./$(OBJDIR)/$(PROGRAM).exe +include <$(DEPTH)\config\config.mak> + +# let manifest generate C_OBJS, it will prepend ./$(OBJDIR)/ +# rules.mak will append C_OBJS onto OBJS. +# OBJS = $(CSRCS:.c=.obj) + +# include files are looked for in $LINCS and $INCS. +# $LINCS is in manifest.mnw, computed from REQUIRES= +INCS = $(INCS) \ + -I$(DEPTH)/security/lib/cert \ + -I../include \ + $(NULL) + +IGNORE_ME = \ + -I$(DEPTH)/security/lib/key \ + -I$(DEPTH)/security/lib/util \ + $(NULL) + + +WINFE = $(DEPTH)/cmd/winfe/mkfiles$(MOZ_BITS)/x86Dbg + +# these files are the content of libdbm +DBM_LIB = \ + $(WINFE)/DB.obj \ + $(WINFE)/HASH.obj \ + $(WINFE)/H_BIGKEY.obj \ + $(WINFE)/H_PAGE.obj \ + $(WINFE)/H_LOG2.obj \ + $(WINFE)/H_FUNC.obj \ + $(WINFE)/HASH_BUF.obj \ + $(NULL) + +MOZ_LIBS = \ + $(WINFE)/ALLXPSTR.obj \ + $(WINFE)/XP_ERROR.obj \ + $(WINFE)/XPASSERT.obj \ + $(WINFE)/XP_REG.obj \ + $(WINFE)/XP_TRACE.obj \ + $(DBM_LIB) \ + $(WINFE)/XP_STR.obj \ + $(WINFE)/MKTEMP.obj \ + $(NULL) + +SEC_LIBS = \ + $(DIST)/lib/cert$(MOZ_BITS).lib \ + $(DIST)/lib/crypto$(MOZ_BITS).lib \ + $(DIST)/lib/hash$(MOZ_BITS).lib \ + $(DIST)/lib/key$(MOZ_BITS).lib \ + $(DIST)/lib/pkcs7$(MOZ_BITS).lib \ + $(DIST)/lib/secmod$(MOZ_BITS).lib \ + $(DIST)/lib/secutl$(MOZ_BITS).lib \ + $(DIST)/lib/ssl$(MOZ_BITS).lib \ + $(NULL) + +LLFLAGS = $(LLFLAGS) \ + ../lib/$(OBJDIR)/sectool$(MOZ_BITS).lib \ + $(SEC_LIBS) \ + $(MOZ_LIBS) \ + $(DEPTH)/nspr/src/$(OBJDIR)/getopt.obj \ + $(LIBNSPR) \ + $(NULL) + + +include <$(DEPTH)\config\rules.mak> + +INSTALL = $(MAKE_INSTALL) + +objs: $(OBJS) + +$(PROGRAM):: + $(INSTALL) $(DIST)/bin/pr3240.dll ./$(OBJDIR) + +programs: $(PROGRAM) + +install:: $(TARGETS) + $(INSTALL) $(TARGETS) $(DIST)/bin + + +symbols: + @echo "CSRCS = $(CSRCS)" + @echo "INCS = $(INCS)" + @echo "OBJS = $(OBJS)" + @echo "LIBRARY = $(LIBRARY)" + @echo "PROGRAM = $(PROGRAM)" + @echo "TARGETS = $(TARGETS)" + @echo "DIST = $(DIST)" + @echo "VERSION_NUMBER = $(VERSION_NUMBER)" + @echo "WINFE = $(WINFE)" + @echo "DBM_LIB = $(DBM_LIB)" + @echo "INSTALL = $(INSTALL)" + diff --git a/security/nss/cmd/btoa/manifest.mn b/security/nss/cmd/btoa/manifest.mn new file mode 100644 index 000000000..b82b26a5c --- /dev/null +++ b/security/nss/cmd/btoa/manifest.mn @@ -0,0 +1,49 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +# This next line is used by .mk files +# and gets translated into $LINCS in manifest.mnw +# MODULE is implicitly REQUIRED, doesn't need to be listed below. +REQUIRES = seccmd dbm + +DEFINES = -DNSPR20 + +CSRCS = btoa.c + +PROGRAM = btoa + diff --git a/security/nss/cmd/certcgi/HOWTO.txt b/security/nss/cmd/certcgi/HOWTO.txt new file mode 100644 index 000000000..f02ad32fd --- /dev/null +++ b/security/nss/cmd/certcgi/HOWTO.txt @@ -0,0 +1,168 @@ + How to setup your very own Cert-O-Matic Root CA server + +***** BEGIN LICENSE BLOCK ***** +Version: MPL 1.1/GPL 2.0/LGPL 2.1 + +The contents of this file are subject to the Mozilla Public License Version +1.1 (the "License"); you may not use this file except in compliance with +the License. You may obtain a copy of the License at +http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" basis, +WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +for the specific language governing rights and limitations under the +License. + +The Original Code is Netscape security libraries. + +The Initial Developer of the Original Code is Netscape Communications +Corporation. Portions created by the Initial Developer are +Copyright (C) 2001 the Initial Developer. All Rights Reserved. + +Contributor(s): + +Alternatively, the contents of this file may be used under the terms of +either the GNU General Public License Version 2 or later (the "GPL"), or +the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), +in which case the provisions of the GPL or the LGPL are applicable instead +of those above. If you wish to allow use of your version of this file only +under the terms of either the GPL or the LGPL, and not to allow others to +use your version of this file under the terms of the MPL, indicate your +decision by deleting the provisions above and replace them with the notice +and other provisions required by the GPL or the LGPL. If you do not delete +the provisions above, a recipient may use your version of this file under +the terms of any one of the MPL, the GPL or the LGPL. + +***** END LICENSE BLOCK ***** + + How to setup your very own Cert-O-Matic Root CA server + +The program certcgi is part of a small test CA that is used inside +Netscape by the NSS development team. That CA is affectionately known +as "Cert-O-Matic" or "Cert-O-Matic II". It presently runs on a server +named interzone.mcom.com inside Netscape's firewall. + +If you wish to setup your own Cert-O-Matic, here are directions. + +Disclaimer: This program does not follow good practices for root CAs. +It should be used only for playing/testing and never for production use. +Remember, you've been warned! + +Cert-O-Matic consists of some html files, shell scripts, one executable +program that uses NSS and NSPR, the usual set of NSS .db files, and a file +in which to remember the serial number of the last cert issued. The +html files and the source to the executable program are in this directory. +Sample shell scripts are shown below. + +The shell scripts and executable program run as CGI "scripts". The +entire thing runs on an ordinary http web server. It would also run on +an https web server. The shell scripts and html files must be +customized for the server on which they run. + +The package assumes you have a "document root" directory $DOCROOT, and a +"cgi-bin" directory $CGIBIN. In this example, the document root is +assumed to be located in /var/www/htdocs, and the cgi-bin directory in +/var/www/cgi-bin. + +The server is assumed to run all cgi scripts as the user "nobody". +The names of the cgi scripts run directly by the server all end in .cgi +because some servers like it that way. + +Instructions: + +- Create directory $DOCROOT/certomatic +- Copy the following files from nss/cmd/certcgi to $DOCROOT/certomatic + ca.html index.html main.html nscp_ext_form.html stnd_ext_form.html +- Edit the html files, substituting the name of your own server for the + server named in those files. +- In some web page (e.g. your server's home page), provide an html link to + $DOCROOT/certomatic/index.html. This is where users start to get their + own certs from certomatic. +- give these files and directories appropriate permissions. + +- Create directories $CGIBIN/certomatic and $CGIBIN/certomatic/bin + make sure that $CGIBIN/certomatic is writable by "nobody" + +- Create a new set of NSS db files there with the following command: + + certutil -N -d $CGIBIN/certomatic + +- when certutil prompts you for the password, enter the word foo + because that is compiled into the certcgi program. + +- Create the new Root CA cert with this command + + certutil -S -x -d $CGIBIN/certomatic -n "Cert-O-Matic II" \ + -s "CN=Cert-O-Matic II, O=Cert-O-Matic II" -t TCu,cu,cu -k rsa \ + -g 1024 -m 10001 -v 60 + + (adjust the -g, -m and -v parameters to taste. -s and -x must be as +shown.) + +- dump out the new root CA cert in base64 encoding: + + certutil -d $CGIBIN/certomatic -L -n "Cert-O-Matic II" -a > \ + $CGIBIN/certomatic/root.cacert + +- In $CGIBIN/certomatic/bin add two shell scripts - one to download the + root CA cert on demand, and one to run the certcgi program. + +download.cgi, the script to install the root CA cert into a browser on +demand, is this: + +#!/bin/sh +echo "Content-type: application/x-x509-ca-cert" +echo +cat $CGIBIN/certomatic/root.cacert + +You'll have to put the real path into that cat command because CGIBIN +won't be defined when this script is run by the server. + +certcgi.cgi, the script to run the certcgi program is similar to this: + +#!/bin/sh +cd $CGIBIN/certomatic/bin +LD_LIBRARY_PATH=$PLATFORM/lib +export LD_LIBRARY_PATH +$PLATFORM/bin/certcgi $* 2>&1 + +Where $PLATFORM/lib is where the NSPR nad NSS DSOs are located, and +$PLATFORM/bin is where certcgi is located. PLATFORM is not defined when +the server runs this script, so you'll have to substitute the right value +in your script. certcgi requires that the working directory be one level +below the NSS DBs, that is, the DBs are accessed in the directory "..". + +You'll want to provide an html link somewhere to the script that downloads +the root.cacert file. You'll probably want to put that next to the link +that loads the index.html page. On interzone, this is done with the +following html: + +<a href="/certomatic/index.html">Cert-O-Matic II Root CA server</a> +<p> +<a href="/cgi-bin/certomatic/bin/download.cgi">Download and trust Root CA +certificate</a> + +The index.html file in this directory invokes the certcgi.cgi script with +the form post method, so if you change the name of the certcgi.cgi script, +you'll also have to change the index.html file in $DOCROOT/certomatic + +The 4 files used by the certcgi program (the 3 NSS DBs, and the serial +number file) are not required to live in $CGIBIN/certomatic, but they are +required to live in $CWD/.. when certcgi starts. + +Known bugs: + +1. Because multiple of these CAs exist simultaneously, it would be best if +they didn't all have to be called "Cert-O-Matic II", but that string is +presently hard coded into certcgi.c. + +2. the html files in this directory contain numerous extraneous <FORM> tags +which appear to use the post method and have action URLS that are never +actually used. burp.cgi and echoform.cgi are never actually used. This +should be cleaned up. + +3. The html files use <layer> tags which are supported only in Netscape +Navigator and Netscape Communication 4.x browsers. The html files do +not work as intended with Netscape 6.x, Mozilla or Microsoft IE browsers. +The html files should be fixed to work with all those named browsers. + diff --git a/security/nss/cmd/certcgi/Makefile b/security/nss/cmd/certcgi/Makefile new file mode 100644 index 000000000..573c12cac --- /dev/null +++ b/security/nss/cmd/certcgi/Makefile @@ -0,0 +1,76 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + + +include ../platrules.mk + diff --git a/security/nss/cmd/certcgi/ca.html b/security/nss/cmd/certcgi/ca.html new file mode 100644 index 000000000..b9ffd8238 --- /dev/null +++ b/security/nss/cmd/certcgi/ca.html @@ -0,0 +1,48 @@ +<!-- + - The contents of this file are subject to the Mozilla Public + - License Version 1.1 (the "License"); you may not use this file + - except in compliance with the License. You may obtain a copy of + - the License at http://www.mozilla.org/MPL/ + - + - Software distributed under the License is distributed on an "AS + - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + - implied. See the License for the specific language governing + - rights and limitations under 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. + --> + +<form method="post" name="ca_form" action="mailto:jerdonek@netscape.com"> +<input type="radio" name="caChoiceradio" value="SignWithDefaultkey" + onClick="{parent.choice_change(this.form)}"> + Use the Cert-O-matic certificate to issue the cert</p> +<input type="radio" name="caChoiceradio" value="SignWithRandomChain" + onClick="{parent.choice_change(this.form)}"> Use a + <input type="text" size="2" maxsize="2" name="autoCAs"> CA long + automatically generated chain ending with the Cert-O-Matic Cert + (18 maximum)</p> +<input type="radio" name="caChoiceradio" value="SignWithSpecifiedChain" + onClick="{parent.choice_change(this.form)}"> Use a + <input type="text" size="1" maxlength="1" name="manCAs" + onChange="{parent.ca_num_change(this.value,this.form)}"> CA long + user input chain ending in the Cert-O-Matic Cert.</p> +</form> diff --git a/security/nss/cmd/certcgi/ca_form.html b/security/nss/cmd/certcgi/ca_form.html new file mode 100644 index 000000000..43042cb64 --- /dev/null +++ b/security/nss/cmd/certcgi/ca_form.html @@ -0,0 +1,385 @@ +<html> +<!-- + - The contents of this file are subject to the Mozilla Public + - License Version 1.1 (the "License"); you may not use this file + - except in compliance with the License. You may obtain a copy of + - the License at http://www.mozilla.org/MPL/ + - + - Software distributed under the License is distributed on an "AS + - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + - implied. See the License for the specific language governing + - rights and limitations under 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. + --> + <form method="post" name="primary_form" action="http://interzone.mcom.com/burp.cgi"> + <table border=0 cellspacing=10 cellpadding=0> + <tr> + <td> + Common Name:</td><td> <input type="text" name="name" onChange="{window.top.reset_subject('CN=', value, form)}"></p> + </td> + <td></td><td></td><td> + Mail: </td><td><input type="text" name="email" onChange="var temp;{if (email_type[0].checked) {temp = 'MAIL='} else {temp = 'E='}} ;{window.top.reset_subject(temp, value, form)}"></p> + RFC 1274<input type="radio" name="email_type" value="1" onClick="window.top.switch_mail(form)"> + e-mail<input type="radio" name="email_type" value="2" checked onClick="window.top.switch_mail(form)"></td> + <tr> + <td> + Organization: </td><td> <input type="text" name="org" onChange="{window.top.reset_subject('O=', value, form)}"></p></td> + <td></td><td></td><td> + Organizational Unit: </td><td><input type="text" name="org_unit" onChange="{window.top.reset_subject('OU=', value, form)}"></p></td> + <tr> + <td> + RFC 1274 UID: </td><td><input type="text" name="uid" onChange="{window.top.reset_subject('UID=', value, form)}"></p></td> + <td></td><td></td><td> + Locality: </td><td><input type="text" name="loc" onChange="{window.top.reset_subject('L=', value, form)}"></p></td> + <tr> + <td> + State or Province: </td><td><input type="text" name="state" onChange="{window.top.reset_subject('ST=', value, form)}"></p></td> + <td></td><td></td><td> + Country: </td><td><input type="text" size="2" maxsize="2" name="country" onChange="{window.top.reset_subject('C=', value, form)}"></p></td> + </table> + <table border=0 cellspacing=10 cellpadding=0> + <tr> + <td> + Serial Number:</p> + <DD> + <input type="radio" name="serial" value="auto" checked> Auto Generate</P> + <DD> + <input type="radio" name="serial" value="input"> + Use this value: <input type="text" name="serial_value" size="8" maxlength="8"></p> + </td> + <td></td><td></td><td></td><td></td> + <td> + X.509 version:</p> + <DD> + <input type="radio" name="ver" value="1" checked> Version 1</p> + <DD> + <input type="radio" name="ver" value="3"> Version 3</P></td> + <td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td><td></td> + <td> + Key Type:</p> + <DD> + <input type="radio" name="keyType" value="rsa" checked> RSA</p> + <DD> + <input type="radio" name="keyType" value="dsa"> DSA</P></td> + </table> + DN: <input type="text" name="subject" size="70" onChange="{window.top.reset_subjectFields(form)}"></P> + <Select name="keysize"> + <option>1024 (High Grade) + <option>768 (Medium Grade) + <option>512 (Low Grade) + </select> + </p> + <hr> + </p> + <table border=1 cellspacing=5 cellpadding=5> + <tr> + <td> + <b>Netscape Certificate Type: </b></p> + Activate extension: <input type="checkbox" name="netscape-cert-type"></P> + Critical: <input type="checkbox" name="netscape-cert-type-crit"> + <td> + <input type="checkbox" name="netscape-cert-type-ssl-client"> SSL Client</P> + <input type="checkbox" name="netscape-cert-type-ssl-server"> SSL Server</P> + <input type="checkbox" name="netscape-cert-type-smime"> S/MIME</P> + <input type="checkbox" name="netscape-cert-type-object-signing"> Object Signing</P> + <input type="checkbox" name="netscape-cert-type-reserved"> Reserved for future use (bit 4)</P> + <input type="checkbox" name="netscape-cert-type-ssl-ca"> SSL CA</P> + <input type="checkbox" name="netscape-cert-type-smime-ca"> S/MIME CA</P> + <input type="checkbox" name="netscape-cert-type-object-signing-ca"> Object Signing CA</P> + </tr> + <tr> + <td> + <b>Netscape Base URL:</b></p> + Activate extension: <input type="checkbox" name="netscape-base-url"></P> + Critical: <input type="checkbox" name="netscape-base-url-crit"> + <td> + <input type="text" name="netscape-base-url-text" size="50"> + </tr> + <tr> + <td> + <b>Netscape Revocation URL:</b></p> + Activate extension: <input type="checkbox" name="netscape-revocation-url"></P> + Critical: <input type="checkbox" name="netscape-revocation-url-crit"> + <td> + <input type="text" name="netscape-revocation-url-text" size="50"> + </tr> + <tr> + <td> + <b>Netscape CA Revocation URL:</b></p> + Activate extension: <input type="checkbox" name="netscape-ca-revocation-url"></P> + Critical: <input type="checkbox" name="netscape-ca-revocation-url-crit"> + <td> + <input type="text" name="netscape-ca-revocation-url-text" size="50"> + </tr> + <tr> + <td> + <b>Netscape Certificate Renewal URL:</b></p> + Activate extension: <input type="checkbox" name="netscape-cert-renewal-url"></P> + Critical: <input type="checkbox" name="netscape-cert-renewal-url-crit"> + <td> + <input type="text" name="netscape-cert-renewal-url-text" size="50"> + </tr> + <tr> + <td> + <b>Netscape CA Policy URL:</b></p> + Activate extension: <input type="checkbox" name="netscape-ca-policy-url"></P> + Critical: <input type="checkbox" name="netscape-ca-policy-url-crit"> + <td> + <input type="text" name="netscape-ca-policy-url-text" size="50"> + </tr> + <tr> + <td> + <b>Netscape SSL Server Name:</b></p> + Activate extension: <input type="checkbox" name="netscape-ssl-server-name"></P> + Critical: <input type="checkbox" name="netscape-ssl-server-name-crit"> + <td> + <input type="text" name="netscape-ssl-server-name-text" size="50"> + </tr> + <tr> + <td> + <b>Netscape Comment:</b></p> + Activate extension: <input type="checkbox" name="netscape-comment"></P> + Critical: <input type="checkbox" name="netscape-comment-crit"> + <td> + <textarea name="netscape-comment-text" rows="5" cols="50"></textarea> + </tr> + </table> + </p> + <hr> + </p> + <table border=1 cellspacing=5 cellpadding=5> + <form method="post" name="primary_form" action="http://interzone.mcom.com/burp.cgi"> + <tr> + <td> + <b>Key Usage: </b></p> + Activate extension: <input type="checkbox" name="keyUsage"></P> + Critical: <input type="checkbox" name="keyUsage-crit"> + <td> + <input type="checkbox" name="keyUsage-digitalSignature"> Digital Signature</P> + <input type="checkbox" name="keyUsage-nonRepudiation"> Non Repudiation</P> + <input type="checkbox" name="keyUsage-keyEncipherment"> Key Encipherment</P> + <input type="checkbox" name="keyUsage-dataEncipherment"> Data Encipherment</P> + <input type="checkbox" name="keyUsage-keyAgreement"> Key Agreement</P> + <input type="checkbox" name="keyUsage-keyCertSign"> Key Certificate Signing</P> + <input type="checkbox" name="keyUsage-cRLSign"> CRL Signing</P> + </tr> + <tr> + <td> + <b>Extended Key Usage: </b></p> + Activate extension: <input type="checkbox" name="extKeyUsage"></P> + Critical: <input type="checkbox" name="extKeyUsage-crit"> + <td> + <input type="checkbox" name="extKeyUsage-serverAuth"> Server Auth</P> + <input type="checkbox" name="extKeyUsage-clientAuth"> Client Auth</P> + <input type="checkbox" name="extKeyUsage-codeSign"> Code Signing</P> + <input type="checkbox" name="extKeyUsage-emailProtect"> Email Protection</P> + <input type="checkbox" name="extKeyUsage-timeStamp"> Timestamp</P> + <input type="checkbox" name="extKeyUsage-ocspResponder"> OCSP Responder</P> + <input type="checkbox" name="extKeyUsage-NS-govtApproved"> Step-up</P> + </tr> + <tr> + <td> + <b>Basic Constraints:</b></p> + Activate extension: <input type="checkbox" name="basicConstraints"></P> + Critical: <input type="checkbox" name="basicConstraints-crit"> + <td> + CA:</p> + <dd><input type=radio name="basicConstraints-cA-radio" value="CA"> True</p> + <dd><input type=radio name="basicConstraints-cA-radio" value="NotCA"> False</p> + <input type="checkbox" name="basicConstraints-pathLengthConstraint"> + Include Path length: <input type="text" name="basicConstraints-pathLengthConstraint-text" size="2"></p> + </tr> + <tr> + <td> + <b>Authority Key Identifier:</b></p> + Activate extension: <input type="checkbox" name="authorityKeyIdentifier"> + <td> + <input type="radio" name="authorityKeyIdentifier-radio" value="keyIdentifier"> Key Identider</p> + <input type="radio" name="authorityKeyIdentifier-radio" value="authorityCertIssuer"> Issuer Name and Serial number</p> + </tr> + <tr> + <td> + <b>Subject Key Identifier:</b></p> + Activate extension: <input type="checkbox" name="subjectKeyIdentifier"> + <td> + Key Identifier: + <input type="text" name="subjectKeyIdentifier-text"></p> + This is an:<p> + <dd><dd><input type="radio" name="subjectKeyIdentifier-radio" value="ascii"> ascii text value<p> + <dd><dd><input type="radio" name="subjectKeyIdentifier-radio" value="hex"> hex value<p> + </tr> + <tr> + <td> + <b>Private Key Usage Period:</b></p> + Activate extension: <input type="checkbox" name="privKeyUsagePeriod"></p> + Critical: <input type="checkbox" name="privKeyUsagePeriod-crit"> + <td> + Use:</p> + <dd><input type="radio" name="privKeyUsagePeriod-radio" value="notBefore"> Not Before</p> + <dd><input type="radio" name="privKeyUsagePeriod-radio" value="notAfter"> Not After</p> + <dd><input type="radio" name="privKeyUsagePeriod-radio" value="both" > Both</p> + <b>Not to be used to sign before:</b></p> + <dd><input type="radio" name="privKeyUsagePeriod-notBefore-radio" value="auto"> Set to time of certificate issue</p> + <dd><input type="radio" name="privKeyUsagePeriod-notBefore-radio" value="manual"> Use This value</p> + <dd><dd>(YYYY/MM/DD HH:MM:SS): + <input type="text" name="privKeyUsagePeriod-notBefore-year" size="4" maxlength="4">/ + <input type="text" name="privKeyUsagePeriod-notBefore-month" size="2" maxlength="2">/ + <input type="text" name="privKeyUsagePeriod-notBefore-day" size="2" maxlength="2"> + <input type="text" name="privKeyUsagePeriod-notBefore-hour" size="2" maxlength="2">: + <input type="text" name="privKeyUsagePeriod-notBefore-minute" size="2" maxlength="2">: + <input type="text" name="privKeyUsagePeriod-notBefore-second" size="2" maxlength="2"></p> + <b>Not to be used to sign after:</b></p> + <dd>(YYYY/MM/DD HH:MM:SS): + <input type="text" name="privKeyUsagePeriod-notAfter-year" size="4" maxlength="4">/ + <input type="text" name="privKeyUsagePeriod-notAfter-month" size="2" maxlength="2">/ + <input type="text" name="privKeyUsagePeriod-notAfter-day" size="2" maxlength="2"> + <input type="text" name="privKeyUsagePeriod-notAfter-hour" size="2" maxlength="2">: + <input type="text" name="privKeyUsagePeriod-notAfter-minute" size="2" maxlength="2">: + <input type="text" name="privKeyUsagePeriod-notAfter-second" size="2" maxlength="2"></p> + </tr> + <tr> + <td> + <b>Subject Alternative Name:</b></p> + Activate extension: <input type="checkbox" name="SubAltName"></P> + Critical: <input type="checkbox" name="SubAltName-crit"> + <td> + <table> + <tr> + <td> + General Names:</p> + <select name="SubAltNameSelect" multiple size="10"> + </select></p></p> + <input type="button" name="SubAltName-add" value="Add" onClick="{parent.addSubAltName(this.form)}"> + <input type="button" name="SubAltName-delete" value="Delete" onClick="parent.deleteSubAltName(this.form)"> + </td><td> + <table><tr><td> + Name Type: </td></tr><tr><td> + <input type="radio" name="SubAltNameRadio" value="otherName" onClick="parent.setSubAltNameType(form)"> Other Name, + OID: <input type="text" name="SubAltNameOtherNameOID" size="6"> </td><td> + <input type="radio" name="SubAltNameRadio" value="rfc822Name" onClick="parent.setSubAltNameType(form)"> RFC 822 Name</td></tr><td> + <input type="radio" name="SubAltNameRadio" value="dnsName" onClick="parent.setSubAltNameType(form)"> DNS Name </td><td> + <input type="radio" name="SubAltNameRadio" value="x400" onClick="parent.setSubAltNameType(form)"> X400 Address</td></tr><td> + <input type="radio" name="SubAltNameRadio" value="directoryName" onClick="parent.setSubAltNameType(form)"> Directory Name</td><td> + <input type="radio" name="SubAltNameRadio" value="ediPartyName" onClick="parent.setSubAltNameType(form)"> EDI Party Name</td></tr><td> + <input type="radio" name="SubAltNameRadio" value="URL" onClick="parent.setSubAltNameType(form)"> Uniform Resource Locator</td><td> + <input type="radio" name="SubAltNameRadio" value="ipAddress" onClick="parent.setSubAltNameType(form)"> IP Address</td></tr><td> + <input type="radio" name="SubAltNameRadio" value="regID"onClick="parent.setSubAltNameType(form)"> Registered ID</td><td> + <input type="radio" name="SubAltNameRadio" value="nscpNickname" onClick="parent.setSubAltNameType(form)"> Netscape Certificate Nickname</td><td></tr> + </table> + Name: <input type="text" name="SubAltNameText"> + Binary Encoded: <input type="checkbox" name="SubAltNameDataType" value="binary" onClick="parent.setSubAltNameType(form)"></p> + </tr> + </table> + </tr> + + + <tr> + <td> + <b>Issuer Alternative Name:</b></p> + Activate extension: <input type="checkbox" name="IssuerAltName"></P> + Critical: <input type="checkbox" name="IssuerAltName-crit"> + <td> + <input type="radio" name="IssuerAltNameSourceRadio" value="auto"> Use the Subject Alternative Name from the Issuers Certificate</p> + <input type="radio" name="IssuerAltNameSourceRadio" value="man"> Use this Name: + <table> + <tr> + <td> + General Names:</p> + <select name="IssuerAltNameSelect" multiple size="10"> + </select></p></p> + <input type="button" name="IssuerAltName-add" value="Add" onClick="{parent.addIssuerAltName(this.form)}"> + <input type="button" name="IssuerAltName-delete" value="Delete" onClick="parent.deleteIssuerAltName(this.form)"> + </td><td> + <table><tr><td> + Name Type: </td></tr><tr><td> + <input type="radio" name="IssuerAltNameRadio" value="otherName" onClick="parent.setIssuerAltNameType(form)"> Other Name, + OID: <input type="text" name="IssuerAltNameOtherNameOID" size="6"> </td><td> + <input type="radio" name="IssuerAltNameRadio" value="rfc822Name" onClick="parent.setIssuerAltNameType(form)"> RFC 822 Name</td></tr><td> + <input type="radio" name="IssuerAltNameRadio" value="dnsName" onClick="parent.setIssuerAltNameType(form)"> DNS Name </td><td> + <input type="radio" name="IssuerAltNameRadio" value="x400" onClick="parent.setIssuerAltNameType(form)"> X400 Address</td></tr><td> + <input type="radio" name="IssuerAltNameRadio" value="directoryName" onClick="parent.setIssuerAltNameType(form)"> Directory Name</td><td> + <input type="radio" name="IssuerAltNameRadio" value="ediPartyName" onClick="parent.setIssuerAltNameType(form)"> EDI Party Name</td></tr><td> + <input type="radio" name="IssuerAltNameRadio" value="URL" onClick="parent.setIssuerAltNameType(form)"> Uniform Resource Locator</td><td> + <input type="radio" name="IssuerAltNameRadio" value="ipAddress" onClick="parent.setIssuerAltNameType(form)"> IP Address</td></tr><td> + <input type="radio" name="IssuerAltNameRadio" value="regID" onClick="parent.setIssuerAltNameType(form)"> Registered ID</td><td></tr> + </table> + Name: <input type="text" name="IssuerAltNameText"> + Binary Encoded: <input type="checkbox" name="IssuerAltNameDataType" value="binary" onClick="parent.setIssuerAltNameType(form)"></p> + </tr> + </table> + </tr> + + <tr> + <td> + <b>Name Constraints:</b></p> + Activate extension: <input type="checkbox" name="NameConstraints"></P> + <td> + <table> + <tr> + <td> + Name Constraints:</p> + + + <select name="NameConstraintSelect" multiple size="10"> + </select></p></p> + <input type="button" name="NameConstraint-add" value="Add" onClick="{parent.addNameConstraint(this.form)}"> + <input type="button" name="NameConstraint-delete" value="Delete" onClick="parent.deleteNameConstraint(this.form)"> + </td><td> + <table><tr><td> + Name Type: </td></tr><tr><td> + <input type="radio" name="NameConstraintRadio" value="otherName" onClick="parent.setNameConstraintNameType(form)"> Other Name, + OID: <input type="text" name="NameConstraintOtherNameOID" size="6"> </td><td> + <input type="radio" name="NameConstraintRadio" value="rfc822Name" onClick="parent.setNameConstraintNameType(form)"> RFC 822 Name</td></tr><td> + <input type="radio" name="NameConstraintRadio" value="dnsName" onClick="parent.setNameConstraintNameType(form)"> DNS Name </td><td> + <input type="radio" name="NameConstraintRadio" value="x400" onClick="parent.setNameConstraintNameType(form)"> X400 Address</td></tr><td> + <input type="radio" name="NameConstraintRadio" value="directoryName" onClick="parent.setNameConstraintNameType(form)"> Directory Name</td><td> + <input type="radio" name="NameConstraintRadio" value="ediPartyName" onClick="parent.setNameConstraintNameType(form)"> EDI Party Name</td></tr><td> + <input type="radio" name="NameConstraintRadio" value="URL" onClick="parent.setNameConstraintNameType(form)"> Uniform Resource Locator</td><td> + <input type="radio" name="NameConstraintRadio" value="ipAddress" onClick="parent.setNameConstraintNameType(form)"> IP Address</td></tr><td> + <input type="radio" name="NameConstraintRadio" value="regID" onClick="parent.setNameConstraintNameType(form)"> Registered ID</td><td></tr> + </table> + Name: <input type="text" name="NameConstraintText"> + Binary Encoded: <input type="checkbox" name="NameConstraintNameDataType" value="binary" onClick="parent.setNameConstraintNameType(form)"></p> + Constraint type:<p> + <dd><input type="radio" name="NameConstraintTypeRadio" value="permited"> permited<p> + <dd><input type="radio" name="NameConstraintTypeRadio" value="excluded"> excluded<p> + Minimum: <input type="text" name="NameConstraintMin" size="8" maxlength="8"></p> + Maximum: <input type="text" name="NameConstraintMax" size="8" maxlength="8"></p> + + + + </tr> + </table> + </tr> + </table> + </form> + + + + + + + + + + diff --git a/security/nss/cmd/certcgi/certcgi.c b/security/nss/cmd/certcgi/certcgi.c new file mode 100644 index 000000000..5377a76a7 --- /dev/null +++ b/security/nss/cmd/certcgi/certcgi.c @@ -0,0 +1,2434 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* Cert-O-Matic CGI */ + + +#include "nspr.h" +#include "prtypes.h" +#include "prtime.h" +#include "prlong.h" + +#include "pk11func.h" +#include "cert.h" +#include "cryptohi.h" +#include "secoid.h" +#include "secder.h" +#include "genname.h" +#include "xconst.h" +#include "secutil.h" +#include "pqgutil.h" +#include "certxutl.h" +#include "secrng.h" /* for RNG_ */ +#include "nss.h" + + +/* #define TEST 1 */ +/* #define FILEOUT 1 */ +/* #define OFFLINE 1 */ +#define START_FIELDS 100 +#define PREFIX_LEN 6 +#define SERIAL_FILE "../serial" +#define DB_DIRECTORY ".." + +static char *progName; + +typedef struct PairStr Pair; + +struct PairStr { + char *name; + char *data; +}; + + +char prefix[PREFIX_LEN]; + + +const SEC_ASN1Template CERTIA5TypeTemplate[] = { + { SEC_ASN1_IA5_STRING } +}; + + + +SECKEYPrivateKey *privkeys[9] = {NULL, NULL, NULL, NULL, NULL, NULL, NULL, + NULL, NULL}; + + +#ifdef notdef +const SEC_ASN1Template CERT_GeneralNameTemplate[] = { + { SEC_ASN1_SEQUENCE_OF, 0, SEC_AnyTemplate } +}; +#endif + + +static void +error_out(char *error_string) +{ + printf("Content-type: text/plain\n\n"); + printf(error_string); + fflush(stderr); + fflush(stdout); + exit(1); +} + +static void +error_allocate(void) +{ + error_out("ERROR: Unable to allocate memory"); +} + + +static char * +make_copy_string(char *read_pos, + int length, + char sentinal_value) + /* copys string from to a new string it creates and + returns a pointer to the new string */ +{ + int remaining = length; + char *write_pos; + char *new; + + new = write_pos = (char *) PORT_Alloc (length); + if (new == NULL) { + error_allocate(); + } + while (*read_pos != sentinal_value) { + if (remaining == 1) { + remaining += length; + length = length * 2; + new = PORT_Realloc(new,length); + if (new == NULL) { + error_allocate(); + } + write_pos = new + length - remaining; + } + *write_pos = *read_pos; + ++write_pos; + ++read_pos; + remaining = remaining - 1; + } + *write_pos = '\0'; + return new; +} + + +static char * +PasswordStub(PK11SlotInfo *slot, + void *cx) +{ + return NULL; +} + + +static SECStatus +clean_input(Pair *data) + /* converts the non-alphanumeric characters in a form post + from hex codes back to characters */ +{ + int length; + int hi_digit; + int low_digit; + char character; + char *begin_pos; + char *read_pos; + char *write_pos; + PRBool name = PR_TRUE; + + begin_pos = data->name; + while (begin_pos != NULL) { + length = strlen(begin_pos); + read_pos = write_pos = begin_pos; + while ((read_pos - begin_pos) < length) { + if (*read_pos == '+') { + *read_pos = ' '; + } + if (*read_pos == '%') { + hi_digit = *(read_pos + 1); + low_digit = *(read_pos +2); + read_pos += 3; + if (isdigit(hi_digit)){ + hi_digit = hi_digit - '0'; + } else { + hi_digit = toupper(hi_digit); + if (isxdigit(hi_digit)) { + hi_digit = (hi_digit - 'A') + 10; + } else { + error_out("ERROR: Form data incorrectly formated"); + } + } + if (isdigit(low_digit)){ + low_digit = low_digit - '0'; + } else { + low_digit = toupper(low_digit); + if ((low_digit >='A') && (low_digit <= 'F')) { + low_digit = (low_digit - 'A') + 10; + } else { + error_out("ERROR: Form data incorrectly formated"); + } + } + character = (hi_digit << 4) | low_digit; + if (character != 10) { + *write_pos = character; + ++write_pos; + } + } else { + *write_pos = *read_pos; + ++write_pos; + ++read_pos; + } + } + *write_pos = '\0'; + if (name == PR_TRUE) { + begin_pos = data->data; + name = PR_FALSE; + } else { + data++; + begin_pos = data->name; + name = PR_TRUE; + } + } + return SECSuccess; +} + +static char * +make_name(char *new_data) + /* gets the next field name in the input string and returns + a pointer to a string containing a copy of it */ +{ + int length = 20; + char *name; + + name = make_copy_string(new_data, length, '='); + return name; +} + +static char * +make_data(char *new_data) + /* gets the data for the next field in the input string + and returns a pointer to a string containing it */ +{ + int length = 100; + char *data; + char *read_pos; + + read_pos = new_data; + while (*(read_pos - 1) != '=') { + ++read_pos; + } + data = make_copy_string(read_pos, length, '&'); + return data; +} + + +static Pair +make_pair(char *new_data) + /* makes a pair name/data pair from the input string */ +{ + Pair temp; + + temp.name = make_name(new_data); + temp.data = make_data(new_data); + return temp; +} + + + +static Pair * +make_datastruct(char *data, int len) + /* parses the input from the form post into a data + structure of field name/data pairs */ +{ + Pair *datastruct; + Pair *current; + char *curr_pos; + int fields = START_FIELDS; + int remaining = START_FIELDS; + + curr_pos = data; + datastruct = current = (Pair *) PORT_Alloc(fields * sizeof(Pair)); + if (datastruct == NULL) { + error_allocate(); + } + while (curr_pos - data < len) { + if (remaining == 1) { + remaining += fields; + fields = fields * 2; + datastruct = (Pair *) PORT_Realloc + (datastruct, fields * sizeof(Pair)); + if (datastruct == NULL) { + error_allocate(); + } + current = datastruct + (fields - remaining); + } + *current = make_pair(curr_pos); + while (*curr_pos != '&') { + ++curr_pos; + } + ++curr_pos; + ++current; + remaining = remaining - 1; + } + current->name = NULL; + return datastruct; +} + +static char * +return_name(Pair *data_struct, + int n) + /* returns a pointer to the name of the nth + (starting from 0) item in the data structure */ +{ + char *name; + + if ((data_struct + n)->name != NULL) { + name = (data_struct + n)->name; + return name; + } else { + return NULL; + } +} + +static char * +return_data(Pair *data_struct,int n) + /* returns a pointer to the data of the nth (starting from 0) + itme in the data structure */ +{ + char *data; + + data = (data_struct + n)->data; + return data; +} + + +static char * +add_prefix(char *field_name) +{ + extern char prefix[PREFIX_LEN]; + int i = 0; + char *rv; + char *write; + + rv = write = PORT_Alloc(PORT_Strlen(prefix) + PORT_Strlen(field_name) + 1); + for(i = 0; i < PORT_Strlen(prefix); i++) { + *write = prefix[i]; + write++; + } + *write = '\0'; + rv = PORT_Strcat(rv,field_name); + return rv; +} + + +static char * +find_field(Pair *data, + char *field_name, + PRBool add_pre) + /* returns a pointer to the data of the first pair + thats name matches the string it is passed */ +{ + int i = 0; + char *retrieved; + int found = 0; + + if (add_pre) { + field_name = add_prefix(field_name); + } + while(return_name(data, i) != NULL) { + if (PORT_Strcmp(return_name(data, i), field_name) == 0) { + retrieved = return_data(data, i); + found = 1; + break; + } + i++; + } + if (!found) { + retrieved = NULL; + } + return retrieved; +} + +static PRBool +find_field_bool(Pair *data, + char *fieldname, + PRBool add_pre) +{ + char *rv; + + rv = find_field(data, fieldname, add_pre); + + if ((rv != NULL) && (PORT_Strcmp(rv, "true")) == 0) { + return PR_TRUE; + } else { + return PR_FALSE; + } +} + +static char * +update_data_by_name(Pair *data, + char *field_name, + char *new_data) + /* replaces the data in the data structure associated with + a name with new data, returns null if not found */ +{ + int i = 0; + int found = 0; + int length = 100; + char *new; + + while (return_name(data, i) != NULL) { + if (PORT_Strcmp(return_name(data, i), field_name) == 0) { + new = make_copy_string( new_data, length, '\0'); + PORT_Free(return_data(data, i)); + found = 1; + (*(data + i)).data = new; + break; + } + i++; + } + if (!found) { + new = NULL; + } + return new; +} + +static char * +update_data_by_index(Pair *data, + int n, + char *new_data) + /* replaces the data of a particular index in the data structure */ +{ + int length = 100; + char *new; + + new = make_copy_string(new_data, length, '\0'); + PORT_Free(return_data(data, n)); + (*(data + n)).data = new; + return new; +} + + +static Pair * +add_field(Pair *data, + char* field_name, + char* field_data) + /* adds a new name/data pair to the data structure */ +{ + int i = 0; + int j; + int name_length = 100; + int data_length = 100; + + while(return_name(data, i) != NULL) { + i++; + } + j = START_FIELDS; + while ( j < (i + 1) ) { + j = j * 2; + } + if (j == (i + 1)) { + data = (Pair *) PORT_Realloc(data, (j * 2) * sizeof(Pair)); + if (data == NULL) { + error_allocate(); + } + } + (*(data + i)).name = make_copy_string(field_name, name_length, '\0'); + (*(data + i)).data = make_copy_string(field_data, data_length, '\0'); + (data + i + 1)->name = NULL; + return data; +} + + +static CERTCertificateRequest * +makeCertReq(Pair *form_data, + int which_priv_key) + /* makes and encodes a certrequest */ +{ + + PK11SlotInfo *slot; + CERTCertificateRequest *certReq = NULL; + CERTSubjectPublicKeyInfo *spki; + SECKEYPrivateKey *privkey = NULL; + SECKEYPublicKey *pubkey = NULL; + CERTName *name; + char *key; + extern SECKEYPrivateKey *privkeys[9]; + int keySizeInBits; + char *challenge = "foo"; + SECStatus rv = SECSuccess; + PQGParams *pqgParams = NULL; + PQGVerify *pqgVfy = NULL; + + name = CERT_AsciiToName(find_field(form_data, "subject", PR_TRUE)); + if (name == NULL) { + error_out("ERROR: Unable to create Subject Name"); + } + key = find_field(form_data, "key", PR_TRUE); + if (key == NULL) { + switch (*find_field(form_data, "keysize", PR_TRUE)) { + case '0': + keySizeInBits = 2048; + break; + case '1': + keySizeInBits = 1024; + break; + case '2': + keySizeInBits = 512; + break; + default: + error_out("ERROR: Unsupported Key length selected"); + } + if (find_field_bool(form_data, "keyType-dsa", PR_TRUE)) { + rv = PQG_ParamGen(keySizeInBits, &pqgParams, &pqgVfy); + if (rv != SECSuccess) { + error_out("ERROR: Unable to generate PQG parameters"); + } + slot = PK11_GetBestSlot(CKM_DSA_KEY_PAIR_GEN, NULL); + privkey = PK11_GenerateKeyPair(slot, CKM_DSA_KEY_PAIR_GEN, + pqgParams,&pubkey, PR_FALSE, + PR_TRUE, NULL); + } else { + privkey = SECKEY_CreateRSAPrivateKey(keySizeInBits, &pubkey, NULL); + } + privkeys[which_priv_key] = privkey; + spki = SECKEY_CreateSubjectPublicKeyInfo(pubkey); + } else { + spki = SECKEY_ConvertAndDecodePublicKeyAndChallenge(key, challenge, + NULL); + if (spki == NULL) { + error_out("ERROR: Unable to decode Public Key and Challenge String"); + } + } + certReq = CERT_CreateCertificateRequest(name, spki, NULL); + if (certReq == NULL) { + error_out("ERROR: Unable to create Certificate Request"); + } + if (pubkey != NULL) { + SECKEY_DestroyPublicKey(pubkey); + } + if (spki != NULL) { + SECKEY_DestroySubjectPublicKeyInfo(spki); + } + if (pqgParams != NULL) { + PQG_DestroyParams(pqgParams); + } + if (pqgVfy != NULL) { + PQG_DestroyVerify(pqgVfy); + } + return certReq; +} + + + +static CERTCertificate * +MakeV1Cert(CERTCertDBHandle *handle, + CERTCertificateRequest *req, + char *issuerNameStr, + PRBool selfsign, + int serialNumber, + int warpmonths, + Pair *data) +{ + CERTCertificate *issuerCert = NULL; + CERTValidity *validity; + CERTCertificate *cert = NULL; + PRExplodedTime printableTime; + PRTime now, + after; + SECStatus rv; + + + + if ( !selfsign ) { + issuerCert = CERT_FindCertByNameString(handle, issuerNameStr); + if (!issuerCert) { + error_out("ERROR: Could not find issuer's certificate"); + return NULL; + } + } + if (find_field_bool(data, "manValidity", PR_TRUE)) { + rv = DER_AsciiToTime(&now, find_field(data, "notBefore", PR_TRUE)); + } else { + now = PR_Now(); + } + PR_ExplodeTime (now, PR_GMTParameters, &printableTime); + if ( warpmonths ) { + printableTime.tm_month += warpmonths; + now = PR_ImplodeTime (&printableTime); + PR_ExplodeTime (now, PR_GMTParameters, &printableTime); + } + if (find_field_bool(data, "manValidity", PR_TRUE)) { + rv = DER_AsciiToTime(&after, find_field(data, "notAfter", PR_TRUE)); + PR_ExplodeTime (after, PR_GMTParameters, &printableTime); + } else { + printableTime.tm_month += 3; + after = PR_ImplodeTime (&printableTime); + } + /* note that the time is now in micro-second unit */ + validity = CERT_CreateValidity (now, after); + + if ( selfsign ) { + cert = CERT_CreateCertificate + (serialNumber,&(req->subject), validity, req); + } else { + cert = CERT_CreateCertificate + (serialNumber,&(issuerCert->subject), validity, req); + } + + CERT_DestroyValidity(validity); + if ( issuerCert ) { + CERT_DestroyCertificate (issuerCert); + } + return(cert); +} + +static int +get_serial_number(Pair *data) +{ + int serial = 0; + int error; + char *filename = SERIAL_FILE; + char *SN; + FILE *serialFile; + + + if (find_field_bool(data, "serial-auto", PR_TRUE)) { + serialFile = fopen(filename, "r"); + if (serialFile != NULL) { + fread(&serial, sizeof(int), 1, serialFile); + if (ferror(serialFile) != 0) { + error_out("Error: Unable to read serial number file"); + } + if (serial == 4294967295) { + serial = 21; + } + fclose(serialFile); + ++serial; + serialFile = fopen(filename,"w"); + if (serialFile == NULL) { + error_out("ERROR: Unable to open serial number file for writing"); + } + fwrite(&serial, sizeof(int), 1, serialFile); + if (ferror(serialFile) != 0) { + error_out("Error: Unable to write to serial number file"); + } + } else { + fclose(serialFile); + serialFile = fopen(filename,"w"); + if (serialFile == NULL) { + error_out("ERROR: Unable to open serial number file"); + } + serial = 21; + fwrite(&serial, sizeof(int), 1, serialFile); + if (ferror(serialFile) != 0) { + error_out("Error: Unable to write to serial number file"); + } + error = ferror(serialFile); + if (error != 0) { + error_out("ERROR: Unable to write to serial file"); + } + } + fclose(serialFile); + } else { + SN = find_field(data, "serial_value", PR_TRUE); + while (*SN != '\0') { + serial = serial * 16; + if ((*SN >= 'A') && (*SN <='F')) { + serial += *SN - 'A' + 10; + } else { + if ((*SN >= 'a') && (*SN <='f')) { + serial += *SN - 'a' + 10; + } else { + serial += *SN - '0'; + } + } + ++SN; + } + } + return serial; +} + + + +typedef SECStatus (* EXTEN_VALUE_ENCODER) + (PRArenaPool *extHandle, void *value, SECItem *encodedValue); + +static SECStatus +EncodeAndAddExtensionValue( + PRArenaPool *arena, + void *extHandle, + void *value, + PRBool criticality, + int extenType, + EXTEN_VALUE_ENCODER EncodeValueFn) +{ + SECItem encodedValue; + SECStatus rv; + + + encodedValue.data = NULL; + encodedValue.len = 0; + rv = (*EncodeValueFn)(arena, value, &encodedValue); + if (rv != SECSuccess) { + error_out("ERROR: Unable to encode extension value"); + } + rv = CERT_AddExtension + (extHandle, extenType, &encodedValue, criticality, PR_TRUE); + return (rv); +} + + + +static SECStatus +AddKeyUsage (void *extHandle, + Pair *data) +{ + SECItem bitStringValue; + unsigned char keyUsage = 0x0; + + if (find_field_bool(data,"keyUsage-digitalSignature", PR_TRUE)){ + keyUsage |= (0x80 >> 0); + } + if (find_field_bool(data,"keyUsage-nonRepudiation", PR_TRUE)){ + keyUsage |= (0x80 >> 1); + } + if (find_field_bool(data,"keyUsage-keyEncipherment", PR_TRUE)){ + keyUsage |= (0x80 >> 2); + } + if (find_field_bool(data,"keyUsage-dataEncipherment", PR_TRUE)){ + keyUsage |= (0x80 >> 3); + } + if (find_field_bool(data,"keyUsage-keyAgreement", PR_TRUE)){ + keyUsage |= (0x80 >> 4); + } + if (find_field_bool(data,"keyUsage-keyCertSign", PR_TRUE)) { + keyUsage |= (0x80 >> 5); + } + if (find_field_bool(data,"keyUsage-cRLSign", PR_TRUE)) { + keyUsage |= (0x80 >> 6); + } + + bitStringValue.data = &keyUsage; + bitStringValue.len = 1; + + return (CERT_EncodeAndAddBitStrExtension + (extHandle, SEC_OID_X509_KEY_USAGE, &bitStringValue, + (find_field_bool(data, "keyUsage-crit", PR_TRUE)))); + +} + +static CERTOidSequence * +CreateOidSequence(void) +{ + CERTOidSequence *rv = (CERTOidSequence *)NULL; + PRArenaPool *arena = (PRArenaPool *)NULL; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if( (PRArenaPool *)NULL == arena ) { + goto loser; + } + + rv = (CERTOidSequence *)PORT_ArenaZAlloc(arena, sizeof(CERTOidSequence)); + if( (CERTOidSequence *)NULL == rv ) { + goto loser; + } + + rv->oids = (SECItem **)PORT_ArenaZAlloc(arena, sizeof(SECItem *)); + if( (SECItem **)NULL == rv->oids ) { + goto loser; + } + + rv->arena = arena; + return rv; + + loser: + if( (PRArenaPool *)NULL != arena ) { + PORT_FreeArena(arena, PR_FALSE); + } + + return (CERTOidSequence *)NULL; +} + +static SECStatus +AddOidToSequence(CERTOidSequence *os, SECOidTag oidTag) +{ + SECItem **oids; + PRUint32 count = 0; + SECOidData *od; + + od = SECOID_FindOIDByTag(oidTag); + if( (SECOidData *)NULL == od ) { + return SECFailure; + } + + for( oids = os->oids; (SECItem *)NULL != *oids; oids++ ) { + count++; + } + + /* ArenaZRealloc */ + + { + PRUint32 i; + + oids = (SECItem **)PORT_ArenaZAlloc(os->arena, sizeof(SECItem *) * (count+2)); + if( (SECItem **)NULL == oids ) { + return SECFailure; + } + + for( i = 0; i < count; i++ ) { + oids[i] = os->oids[i]; + } + + /* ArenaZFree(os->oids); */ + } + + os->oids = oids; + os->oids[count] = &od->oid; + + return SECSuccess; +} + +static SECItem * +EncodeOidSequence(CERTOidSequence *os) +{ + SECItem *rv; + extern const SEC_ASN1Template CERT_OidSeqTemplate[]; + + rv = (SECItem *)PORT_ArenaZAlloc(os->arena, sizeof(SECItem)); + if( (SECItem *)NULL == rv ) { + goto loser; + } + + if( !SEC_ASN1EncodeItem(os->arena, rv, os, CERT_OidSeqTemplate) ) { + goto loser; + } + + return rv; + + loser: + return (SECItem *)NULL; +} + +static SECStatus +AddExtKeyUsage(void *extHandle, Pair *data) +{ + SECStatus rv; + CERTOidSequence *os; + SECItem *value; + PRBool crit; + + os = CreateOidSequence(); + if( (CERTOidSequence *)NULL == os ) { + return SECFailure; + } + + if( find_field_bool(data, "extKeyUsage-serverAuth", PR_TRUE) ) { + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH); + if( SECSuccess != rv ) goto loser; + } + + if( find_field_bool(data, "extKeyUsage-clientAuth", PR_TRUE) ) { + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH); + if( SECSuccess != rv ) goto loser; + } + + if( find_field_bool(data, "extKeyUsage-codeSign", PR_TRUE) ) { + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CODE_SIGN); + if( SECSuccess != rv ) goto loser; + } + + if( find_field_bool(data, "extKeyUsage-emailProtect", PR_TRUE) ) { + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT); + if( SECSuccess != rv ) goto loser; + } + + if( find_field_bool(data, "extKeyUsage-timeStamp", PR_TRUE) ) { + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_TIME_STAMP); + if( SECSuccess != rv ) goto loser; + } + + if( find_field_bool(data, "extKeyUsage-ocspResponder", PR_TRUE) ) { + rv = AddOidToSequence(os, SEC_OID_OCSP_RESPONDER); + if( SECSuccess != rv ) goto loser; + } + + if( find_field_bool(data, "extKeyUsage-NS-govtApproved", PR_TRUE) ) { + rv = AddOidToSequence(os, SEC_OID_NS_KEY_USAGE_GOVT_APPROVED); + if( SECSuccess != rv ) goto loser; + } + + value = EncodeOidSequence(os); + + crit = find_field_bool(data, "extKeyUsage-crit", PR_TRUE); + + rv = CERT_AddExtension(extHandle, SEC_OID_X509_EXT_KEY_USAGE, value, + crit, PR_TRUE); + /*FALLTHROUGH*/ + loser: + CERT_DestroyOidSequence(os); + return rv; +} + +static SECStatus +AddSubKeyID(void *extHandle, + Pair *data, + CERTCertificate *subjectCert) +{ + SECItem encodedValue; + SECStatus rv; + char *read; + char *write; + char *first; + char character; + int high_digit = 0, + low_digit = 0; + int len; + PRBool odd = PR_FALSE; + + + encodedValue.data = NULL; + encodedValue.len = 0; + first = read = write = find_field(data,"subjectKeyIdentifier-text", + PR_TRUE); + len = PORT_Strlen(first); + odd = ((len % 2) != 0 ) ? PR_TRUE : PR_FALSE; + if (find_field_bool(data, "subjectKeyIdentifier-radio-hex", PR_TRUE)) { + if (odd) { + error_out("ERROR: Improperly formated subject key identifier, hex values must be expressed as an octet string"); + } + while (*read != '\0') { + if (!isxdigit(*read)) { + error_out("ERROR: Improperly formated subject key identifier"); + } + *read = toupper(*read); + if ((*read >= 'A') && (*read <= 'F')) { + high_digit = *read - 'A' + 10; + } else { + high_digit = *read - '0'; + } + ++read; + if (!isxdigit(*read)) { + error_out("ERROR: Improperly formated subject key identifier"); + } + *read = toupper(*read); + if ((*read >= 'A') && (*read <= 'F')) { + low_digit = *(read) - 'A' + 10; + } else { + low_digit = *(read) - '0'; + } + character = (high_digit << 4) | low_digit; + *write = character; + ++write; + ++read; + } + *write = '\0'; + len = write - first; + } + subjectCert->subjectKeyID.data = (unsigned char *) find_field + (data,"subjectKeyIdentifier-text", PR_TRUE); + subjectCert->subjectKeyID.len = len; + rv = CERT_EncodeSubjectKeyID + (NULL, find_field(data,"subjectKeyIdentifier-text", PR_TRUE), + len, &encodedValue); + if (rv) { + return (rv); + } + return (CERT_AddExtension(extHandle, SEC_OID_X509_SUBJECT_KEY_ID, + &encodedValue, PR_FALSE, PR_TRUE)); +} + + +static SECStatus +AddAuthKeyID (void *extHandle, + Pair *data, + char *issuerNameStr, + CERTCertDBHandle *handle) +{ + CERTAuthKeyID *authKeyID = NULL; + PRArenaPool *arena = NULL; + SECStatus rv = SECSuccess; + CERTCertificate *issuerCert = NULL; + CERTGeneralName *genNames; + CERTName *directoryName = NULL; + + + issuerCert = CERT_FindCertByNameString(handle, issuerNameStr); + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) { + error_allocate(); + } + + authKeyID = PORT_ArenaZAlloc (arena, sizeof (CERTAuthKeyID)); + if (authKeyID == NULL) { + error_allocate(); + } + if (find_field_bool(data, "authorityKeyIdentifier-radio-keyIdentifier", + PR_TRUE)) { + authKeyID->keyID.data = PORT_ArenaAlloc (arena, PORT_Strlen + ((char *)issuerCert->subjectKeyID.data)); + if (authKeyID->keyID.data == NULL) { + error_allocate(); + } + PORT_Memcpy (authKeyID->keyID.data, issuerCert->subjectKeyID.data, + authKeyID->keyID.len = + PORT_Strlen((char *)issuerCert->subjectKeyID.data)); + } else { + + PORT_Assert (arena); + genNames = (CERTGeneralName *) PORT_ArenaZAlloc (arena, (sizeof(CERTGeneralName))); + if (genNames == NULL){ + error_allocate(); + } + genNames->l.next = genNames->l.prev = &(genNames->l); + genNames->type = certDirectoryName; + + directoryName = CERT_AsciiToName(issuerCert->subjectName); + if (!directoryName) { + error_out("ERROR: Unable to create Directory Name"); + } + rv = CERT_CopyName (arena, &genNames->name.directoryName, + directoryName); + CERT_DestroyName (directoryName); + if (rv != SECSuccess) { + error_out("ERROR: Unable to copy Directory Name"); + } + authKeyID->authCertIssuer = genNames; + if (authKeyID->authCertIssuer == NULL && SECFailure == + PORT_GetError ()) { + error_out("ERROR: Unable to get Issuer General Name for Authority Key ID Extension"); + } + authKeyID->authCertSerialNumber = issuerCert->serialNumber; + } + rv = EncodeAndAddExtensionValue(arena, extHandle, authKeyID, PR_FALSE, + SEC_OID_X509_AUTH_KEY_ID, + (EXTEN_VALUE_ENCODER) + CERT_EncodeAuthKeyID); + if (arena) { + PORT_FreeArena (arena, PR_FALSE); + } + return (rv); +} + + +static SECStatus +AddPrivKeyUsagePeriod(void *extHandle, + Pair *data, + CERTCertificate *cert) +{ + char *notBeforeStr; + char *notAfterStr; + PRArenaPool *arena = NULL; + SECStatus rv = SECSuccess; + PKUPEncodedContext *pkup; + + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) { + error_allocate(); + } + pkup = PORT_ArenaZAlloc (arena, sizeof (PKUPEncodedContext)); + if (pkup == NULL) { + error_allocate(); + } + notBeforeStr = (char *) PORT_Alloc(16 ); + notAfterStr = (char *) PORT_Alloc(16 ); + *notBeforeStr = '\0'; + *notAfterStr = '\0'; + pkup->arena = arena; + pkup->notBefore.len = 0; + pkup->notBefore.data = NULL; + pkup->notAfter.len = 0; + pkup->notAfter.data = NULL; + if (find_field_bool(data, "privKeyUsagePeriod-radio-notBefore", PR_TRUE) || + find_field_bool(data, "privKeyUsagePeriod-radio-both", PR_TRUE)) { + pkup->notBefore.len = 15; + pkup->notBefore.data = (unsigned char *)notBeforeStr; + if (find_field_bool(data, "privKeyUsagePeriod-notBefore-radio-manual", + PR_TRUE)) { + PORT_Strcat(notBeforeStr,find_field(data, + "privKeyUsagePeriod-notBefore-year", + PR_TRUE)); + PORT_Strcat(notBeforeStr,find_field(data, + "privKeyUsagePeriod-notBefore-month", + PR_TRUE)); + PORT_Strcat(notBeforeStr,find_field(data, + "privKeyUsagePeriod-notBefore-day", + PR_TRUE)); + PORT_Strcat(notBeforeStr,find_field(data, + "privKeyUsagePeriod-notBefore-hour", + PR_TRUE)); + PORT_Strcat(notBeforeStr,find_field(data, + "privKeyUsagePeriod-notBefore-minute", + PR_TRUE)); + PORT_Strcat(notBeforeStr,find_field(data, + "privKeyUsagePeriod-notBefore-second", + PR_TRUE)); + if ((*(notBeforeStr + 14) != '\0') || + (!isdigit(*(notBeforeStr + 13))) || + (*(notBeforeStr + 12) >= '5' && *(notBeforeStr + 12) <= '0') || + (!isdigit(*(notBeforeStr + 11))) || + (*(notBeforeStr + 10) >= '5' && *(notBeforeStr + 10) <= '0') || + (!isdigit(*(notBeforeStr + 9))) || + (*(notBeforeStr + 8) >= '2' && *(notBeforeStr + 8) <= '0') || + (!isdigit(*(notBeforeStr + 7))) || + (*(notBeforeStr + 6) >= '3' && *(notBeforeStr + 6) <= '0') || + (!isdigit(*(notBeforeStr + 5))) || + (*(notBeforeStr + 4) >= '1' && *(notBeforeStr + 4) <= '0') || + (!isdigit(*(notBeforeStr + 3))) || + (!isdigit(*(notBeforeStr + 2))) || + (!isdigit(*(notBeforeStr + 1))) || + (!isdigit(*(notBeforeStr + 0))) || + (*(notBeforeStr + 8) == '2' && *(notBeforeStr + 9) >= '4') || + (*(notBeforeStr + 6) == '3' && *(notBeforeStr + 7) >= '1') || + (*(notBeforeStr + 4) == '1' && *(notBeforeStr + 5) >= '2')) { + error_out("ERROR: Improperly formated private key usage period"); + } + *(notBeforeStr + 14) = 'Z'; + *(notBeforeStr + 15) = '\0'; + } else { + if ((*(cert->validity.notBefore.data) > '5') || + ((*(cert->validity.notBefore.data) == '5') && + (*(cert->validity.notBefore.data + 1) != '0'))) { + PORT_Strcat(notBeforeStr, "19"); + } else { + PORT_Strcat(notBeforeStr, "20"); + } + PORT_Strcat(notBeforeStr, (char *)cert->validity.notBefore.data); + } + } + if (find_field_bool(data, "privKeyUsagePeriod-radio-notAfter", PR_TRUE) || + find_field_bool(data, "privKeyUsagePeriod-radio-both", PR_TRUE)) { + pkup->notAfter.len = 15; + pkup->notAfter.data = (unsigned char *)notAfterStr; + PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-year", + PR_TRUE)); + PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-month", + PR_TRUE)); + PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-day", + PR_TRUE)); + PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-hour", + PR_TRUE)); + PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-minute", + PR_TRUE)); + PORT_Strcat(notAfterStr,find_field(data,"privKeyUsagePeriod-notAfter-second", + PR_TRUE)); + if ((*(notAfterStr + 14) != '\0') || + (!isdigit(*(notAfterStr + 13))) || + (*(notAfterStr + 12) >= '5' && *(notAfterStr + 12) <= '0') || + (!isdigit(*(notAfterStr + 11))) || + (*(notAfterStr + 10) >= '5' && *(notAfterStr + 10) <= '0') || + (!isdigit(*(notAfterStr + 9))) || + (*(notAfterStr + 8) >= '2' && *(notAfterStr + 8) <= '0') || + (!isdigit(*(notAfterStr + 7))) || + (*(notAfterStr + 6) >= '3' && *(notAfterStr + 6) <= '0') || + (!isdigit(*(notAfterStr + 5))) || + (*(notAfterStr + 4) >= '1' && *(notAfterStr + 4) <= '0') || + (!isdigit(*(notAfterStr + 3))) || + (!isdigit(*(notAfterStr + 2))) || + (!isdigit(*(notAfterStr + 1))) || + (!isdigit(*(notAfterStr + 0))) || + (*(notAfterStr + 8) == '2' && *(notAfterStr + 9) >= '4') || + (*(notAfterStr + 6) == '3' && *(notAfterStr + 7) >= '1') || + (*(notAfterStr + 4) == '1' && *(notAfterStr + 5) >= '2')) { + error_out("ERROR: Improperly formated private key usage period"); + } + *(notAfterStr + 14) = 'Z'; + *(notAfterStr + 15) = '\0'; + } + + PORT_Assert (arena); + + rv = EncodeAndAddExtensionValue(arena, extHandle, pkup, + find_field_bool(data, + "privKeyUsagePeriod-crit", + PR_TRUE), + SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD, + (EXTEN_VALUE_ENCODER) + CERT_EncodePublicKeyUsagePeriod); + if (arena) { + PORT_FreeArena (arena, PR_FALSE); + } + if (notBeforeStr != NULL) { + PORT_Free(notBeforeStr); + } + if (notAfterStr != NULL) { + PORT_Free(notAfterStr); + } + return (rv); +} + +static SECStatus +AddBasicConstraint(void *extHandle, + Pair *data) +{ + CERTBasicConstraints basicConstraint; + SECItem encodedValue; + SECStatus rv; + + encodedValue.data = NULL; + encodedValue.len = 0; + basicConstraint.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT; + basicConstraint.isCA = (find_field_bool(data,"basicConstraints-cA-radio-CA", + PR_TRUE)); + if (find_field_bool(data,"basicConstraints-pathLengthConstraint", PR_TRUE)){ + basicConstraint.pathLenConstraint = atoi + (find_field(data,"basicConstraints-pathLengthConstraint-text", + PR_TRUE)); + } + + rv = CERT_EncodeBasicConstraintValue (NULL, &basicConstraint, + &encodedValue); + if (rv) + return (rv); + rv = CERT_AddExtension(extHandle, SEC_OID_X509_BASIC_CONSTRAINTS, + &encodedValue, + (find_field_bool(data,"basicConstraints-crit", + PR_TRUE)), PR_TRUE); + + PORT_Free (encodedValue.data); + return (rv); +} + + + +static SECStatus +AddNscpCertType (void *extHandle, + Pair *data) +{ + SECItem bitStringValue; + unsigned char CertType = 0x0; + + if (find_field_bool(data,"netscape-cert-type-ssl-client", PR_TRUE)){ + CertType |= (0x80 >> 0); + } + if (find_field_bool(data,"netscape-cert-type-ssl-server", PR_TRUE)){ + CertType |= (0x80 >> 1); + } + if (find_field_bool(data,"netscape-cert-type-smime", PR_TRUE)){ + CertType |= (0x80 >> 2); + } + if (find_field_bool(data,"netscape-cert-type-object-signing", PR_TRUE)){ + CertType |= (0x80 >> 3); + } + if (find_field_bool(data,"netscape-cert-type-reserved", PR_TRUE)){ + CertType |= (0x80 >> 4); + } + if (find_field_bool(data,"netscape-cert-type-ssl-ca", PR_TRUE)) { + CertType |= (0x80 >> 5); + } + if (find_field_bool(data,"netscape-cert-type-smime-ca", PR_TRUE)) { + CertType |= (0x80 >> 6); + } + if (find_field_bool(data,"netscape-cert-type-object-signing-ca", PR_TRUE)) { + CertType |= (0x80 >> 7); + } + + bitStringValue.data = &CertType; + bitStringValue.len = 1; + + return (CERT_EncodeAndAddBitStrExtension + (extHandle, SEC_OID_NS_CERT_EXT_CERT_TYPE, &bitStringValue, + (find_field_bool(data, "netscape-cert-type-crit", PR_TRUE)))); +} + + +static SECStatus +add_IA5StringExtension(void *extHandle, + char *string, + PRBool crit, + int idtag) +{ + SECItem encodedValue; + SECStatus rv; + + encodedValue.data = NULL; + encodedValue.len = 0; + + rv = CERT_EncodeIA5TypeExtension(NULL, string, &encodedValue); + if (rv) { + return (rv); + } + return (CERT_AddExtension(extHandle, idtag, &encodedValue, crit, PR_TRUE)); +} + +static SECItem * +string_to_oid(char *string) +{ + int i; + int length = 20; + int remaining; + int first_value; + int second_value; + int value; + int oidLength; + unsigned char *oidString; + unsigned char *write; + unsigned char *read; + unsigned char *temp; + SECItem *oid; + + + remaining = length; + i = 0; + while (*string == ' ') { + string++; + } + while (isdigit(*(string + i))) { + i++; + } + if (*(string + i) == '.') { + *(string + i) = '\0'; + } else { + error_out("ERROR: Improperly formated OID"); + } + first_value = atoi(string); + if (first_value < 0 || first_value > 2) { + error_out("ERROR: Improperly formated OID"); + } + string += i + 1; + i = 0; + while (isdigit(*(string + i))) { + i++; + } + if (*(string + i) == '.') { + *(string + i) = '\0'; + } else { + error_out("ERROR: Improperly formated OID"); + } + second_value = atoi(string); + if (second_value < 0 || second_value > 39) { + error_out("ERROR: Improperly formated OID"); + } + oidString = PORT_ZAlloc(2); + *oidString = (first_value * 40) + second_value; + *(oidString + 1) = '\0'; + oidLength = 1; + string += i + 1; + i = 0; + temp = write = PORT_ZAlloc(length); + while (*string != '\0') { + value = 0; + while(isdigit(*(string + i))) { + i++; + } + if (*(string + i) == '\0') { + value = atoi(string); + string += i; + } else { + if (*(string + i) == '.') { + *(string + i) = '\0'; + value = atoi(string); + string += i + 1; + } else { + *(string + i) = '\0'; + i++; + value = atoi(string); + while (*(string + i) == ' ') + i++; + if (*(string + i) != '\0') { + error_out("ERROR: Improperly formated OID"); + } + } + } + i = 0; + while (value != 0) { + if (remaining < 1) { + remaining += length; + length = length * 2; + temp = PORT_Realloc(temp, length); + write = temp + length - remaining; + } + *write = (value & 0x7f) | (0x80); + write++; + remaining--; + value = value >> 7; + } + *temp = *temp & (0x7f); + oidLength += write - temp; + oidString = PORT_Realloc(oidString, (oidLength + 1)); + read = write - 1; + write = oidLength + oidString - 1; + for (i = 0; i < (length - remaining); i++) { + *write = *read; + write--; + read++; + } + write = temp; + remaining = length; + } + *(oidString + oidLength) = '\0'; + oid = (SECItem *) PORT_ZAlloc(sizeof(SECItem)); + oid->data = oidString; + oid->len = oidLength; + PORT_Free(temp); + return oid; +} + +static SECItem * +string_to_ipaddress(char *string) +{ + int i = 0; + int value; + int j = 0; + SECItem *ipaddress; + + + while (*string == ' ') { + string++; + } + ipaddress = (SECItem *) PORT_ZAlloc(sizeof(SECItem)); + ipaddress->data = PORT_ZAlloc(9); + while (*string != '\0' && j < 8) { + while (isdigit(*(string + i))) { + i++; + } + if (*(string + i) == '.') { + *(string + i) = '\0'; + value = atoi(string); + string = string + i + 1; + i = 0; + } else { + if (*(string + i) == '\0') { + value = atoi(string); + string = string + i; + i = 0; + } else { + *(string + i) = '\0'; + while (*(string + i) == ' ') { + i++; + } + if (*(string + i) == '\0') { + value = atoi(string); + string = string + i; + i = 0; + } else { + error_out("ERROR: Improperly formated IP Address"); + } + } + } + if (value >= 0 || value < 256) { + *(ipaddress->data + j) = value; + } else { + error_out("ERROR: Improperly formated IP Address"); + } + j++; + } + *(ipaddress->data + j) = '\0'; + if (j != 4 && j != 8) { + error_out("ERROR: Improperly formated IP Address"); + } + ipaddress->len = j; + return ipaddress; +} + +static SECItem * +string_to_binary(char *string) +{ + SECItem *rv; + int high_digit; + int low_digit; + + rv = (SECItem *) PORT_ZAlloc(sizeof(SECItem)); + if (rv == NULL) { + error_allocate(); + } + rv->data = (unsigned char *) PORT_ZAlloc((PORT_Strlen(string))/3 + 2); + while (!isxdigit(*string)) { + string++; + } + rv->len = 0; + while (*string != '\0') { + if (isxdigit(*string)) { + if (*string >= '0' && *string <= '9') { + high_digit = *string - '0'; + } else { + *string = toupper(*string); + high_digit = *string - 'A'; + } + string++; + if (*string >= '0' && *string <= '9') { + low_digit = *string - '0'; + } else { + *string = toupper(*string); + low_digit = *string = 'A'; + } + (rv->len)++; + } else { + if (*string == ':') { + string++; + } else { + if (*string == ' ') { + while (*string == ' ') { + string++; + } + } + if (*string != '\0') { + error_out("ERROR: Improperly formated binary encoding"); + } + } + } + } + + return rv; +} + +static SECStatus +MakeGeneralName(char *name, + CERTGeneralName *genName, + PRArenaPool *arena) +{ + SECItem *oid; + SECOidData *oidData; + SECItem *ipaddress; + SECItem *temp = NULL; + int i; + int nameType; + PRBool binary = PR_FALSE; + SECStatus rv = SECSuccess; + PRBool nickname; + + PORT_Assert(genName); + PORT_Assert(arena); + nameType = *(name + PORT_Strlen(name) - 1) - '0'; + if (nameType == 0 && *(name +PORT_Strlen(name) - 2) == '1') { + nickname = PR_TRUE; + nameType = certOtherName; + } + if (nameType < 1 || nameType > 9) { + error_out("ERROR: Unknown General Name Type"); + } + *(name + PORT_Strlen(name) - 4) = '\0'; + genName->type = nameType; + + switch (genName->type) { + case certURI: + case certRFC822Name: + case certDNSName: { + genName->name.other.data = (unsigned char *)name; + genName->name.other.len = PORT_Strlen(name); + break; + } + + case certIPAddress: { + ipaddress = string_to_ipaddress(name); + genName->name.other.data = ipaddress->data; + genName->name.other.len = ipaddress->len; + break; + } + + case certRegisterID: { + oid = string_to_oid(name); + genName->name.other.data = oid->data; + genName->name.other.len = oid->len; + break; + } + + case certEDIPartyName: + case certX400Address: { + + genName->name.other.data = PORT_ArenaAlloc (arena, + PORT_Strlen (name) + 2); + if (genName->name.other.data == NULL) { + error_allocate(); + } + + PORT_Memcpy (genName->name.other.data + 2, name, PORT_Strlen (name)); + /* This may not be accurate for all cases. + For now, use this tag type */ + genName->name.other.data[0] = (char)(((genName->type - 1) & + 0x1f)| 0x80); + genName->name.other.data[1] = (char)PORT_Strlen (name); + genName->name.other.len = PORT_Strlen (name) + 2; + break; + } + + case certOtherName: { + i = 0; + if (!nickname) { + while (!isdigit(*(name + PORT_Strlen(name) - i))) { + i++; + } + if (*(name + PORT_Strlen(name) - i) == '1') { + binary = PR_TRUE; + } else { + binary = PR_FALSE; + } + while (*(name + PORT_Strlen(name) - i) != '-') { + i++; + } + *(name + PORT_Strlen(name) - i - 1) = '\0'; + i = 0; + while (*(name + i) != '-') { + i++; + } + *(name + i - 1) = '\0'; + oid = string_to_oid(name + i + 2); + } else { + oidData = SECOID_FindOIDByTag(SEC_OID_NETSCAPE_NICKNAME); + oid = &oidData->oid; + while (*(name + PORT_Strlen(name) - i) != '-') { + i++; + } + *(name + PORT_Strlen(name) - i) = '\0'; + } + genName->name.OthName.oid.data = oid->data; + genName->name.OthName.oid.len = oid->len; + if (binary) { + temp = string_to_binary(name); + genName->name.OthName.name.data = temp->data; + genName->name.OthName.name.len = temp->len; + } else { + temp = (SECItem *) PORT_ZAlloc(sizeof(SECItem)); + if (temp == NULL) { + error_allocate(); + } + temp->data = (unsigned char *)name; + temp->len = PORT_Strlen(name); + SEC_ASN1EncodeItem (arena, &(genName->name.OthName.name), temp, + CERTIA5TypeTemplate); + } + PORT_Free(temp); + break; + } + + case certDirectoryName: { + CERTName *directoryName = NULL; + + directoryName = CERT_AsciiToName (name); + if (!directoryName) { + error_out("ERROR: Improperly formated alternative name"); + break; + } + rv = CERT_CopyName (arena, &genName->name.directoryName, + directoryName); + CERT_DestroyName (directoryName); + + break; + } + } + genName->l.next = &(genName->l); + genName->l.prev = &(genName->l); + return rv; +} + + +static CERTGeneralName * +MakeAltName(Pair *data, + char *which, + PRArenaPool *arena) +{ + CERTGeneralName *SubAltName; + CERTGeneralName *current; + CERTGeneralName *newname; + char *name = NULL; + SECStatus rv = SECSuccess; + int len; + + + len = PORT_Strlen(which); + name = find_field(data, which, PR_TRUE); + SubAltName = current = (CERTGeneralName *) PORT_ZAlloc + (sizeof(CERTGeneralName)); + if (current == NULL) { + error_allocate(); + } + while (name != NULL) { + + rv = MakeGeneralName(name, current, arena); + + if (rv != SECSuccess) { + break; + } + if (*(which + len -1) < '9') { + *(which + len - 1) = *(which + len - 1) + 1; + } else { + if (isdigit(*(which + len - 2) )) { + *(which + len - 2) = *(which + len - 2) + 1; + *(which + len - 1) = '0'; + } else { + *(which + len - 1) = '1'; + *(which + len) = '0'; + *(which + len + 1) = '\0'; + len++; + } + } + len = PORT_Strlen(which); + name = find_field(data, which, PR_TRUE); + if (name != NULL) { + newname = (CERTGeneralName *) PORT_ZAlloc(sizeof(CERTGeneralName)); + if (newname == NULL) { + error_allocate(); + } + current->l.next = &(newname->l); + newname->l.prev = &(current->l); + current = newname; + newname = NULL; + } else { + current->l.next = &(SubAltName->l); + SubAltName->l.prev = &(current->l); + } + } + if (rv == SECFailure) { + return NULL; + } + return SubAltName; +} + +static CERTNameConstraints * +MakeNameConstraints(Pair *data, + PRArenaPool *arena) +{ + CERTNameConstraints *NameConstraints; + CERTNameConstraint *current = NULL; + CERTNameConstraint *last_permited = NULL; + CERTNameConstraint *last_excluded = NULL; + char *constraint = NULL; + char *which; + SECStatus rv = SECSuccess; + int len; + int i; + long max; + long min; + PRBool permited; + + + NameConstraints = (CERTNameConstraints *) PORT_ZAlloc + (sizeof(CERTNameConstraints)); + which = make_copy_string("NameConstraintSelect0", 25,'\0'); + len = PORT_Strlen(which); + constraint = find_field(data, which, PR_TRUE); + NameConstraints->permited = NameConstraints->excluded = NULL; + while (constraint != NULL) { + current = (CERTNameConstraint *) PORT_ZAlloc + (sizeof(CERTNameConstraint)); + if (current == NULL) { + error_allocate(); + } + i = 0; + while (*(constraint + PORT_Strlen(constraint) - i) != '-') { + i++; + } + *(constraint + PORT_Strlen(constraint) - i - 1) = '\0'; + max = (long) atoi(constraint + PORT_Strlen(constraint) + 3); + if (max > 0) { + (void) SEC_ASN1EncodeInteger(arena, ¤t->max, max); + } + i = 0; + while (*(constraint + PORT_Strlen(constraint) - i) != '-') { + i++; + } + *(constraint + PORT_Strlen(constraint) - i - 1) = '\0'; + min = (long) atoi(constraint + PORT_Strlen(constraint) + 3); + (void) SEC_ASN1EncodeInteger(arena, ¤t->min, min); + while (*(constraint + PORT_Strlen(constraint) - i) != '-') { + i++; + } + *(constraint + PORT_Strlen(constraint) - i - 1) = '\0'; + if (*(constraint + PORT_Strlen(constraint) + 3) == 'p') { + permited = PR_TRUE; + } else { + permited = PR_FALSE; + } + rv = MakeGeneralName(constraint, &(current->name), arena); + + if (rv != SECSuccess) { + break; + } + if (*(which + len - 1) < '9') { + *(which + len - 1) = *(which + len - 1) + 1; + } else { + if (isdigit(*(which + len - 2) )) { + *(which + len - 2) = *(which + len - 2) + 1; + *(which + len - 1) = '0'; + } else { + *(which + len - 1) = '1'; + *(which + len) = '0'; + *(which + len + 1) = '\0'; + len++; + } + } + len = PORT_Strlen(which); + if (permited) { + if (NameConstraints->permited == NULL) { + NameConstraints->permited = last_permited = current; + } + last_permited->l.next = &(current->l); + current->l.prev = &(last_permited->l); + last_permited = current; + } else { + if (NameConstraints->excluded == NULL) { + NameConstraints->excluded = last_excluded = current; + } + last_excluded->l.next = &(current->l); + current->l.prev = &(last_excluded->l); + last_excluded = current; + } + constraint = find_field(data, which, PR_TRUE); + if (constraint != NULL) { + current = (CERTNameConstraint *) PORT_ZAlloc(sizeof(CERTNameConstraint)); + if (current == NULL) { + error_allocate(); + } + } + } + if (NameConstraints->permited != NULL) { + last_permited->l.next = &(NameConstraints->permited->l); + NameConstraints->permited->l.prev = &(last_permited->l); + } + if (NameConstraints->excluded != NULL) { + last_excluded->l.next = &(NameConstraints->excluded->l); + NameConstraints->excluded->l.prev = &(last_excluded->l); + } + if (which != NULL) { + PORT_Free(which); + } + if (rv == SECFailure) { + return NULL; + } + return NameConstraints; +} + + + +static SECStatus +AddAltName(void *extHandle, + Pair *data, + char *issuerNameStr, + CERTCertDBHandle *handle, + int type) +{ + PRBool autoIssuer = PR_FALSE; + PRArenaPool *arena = NULL; + CERTGeneralName *genName = NULL; + CERTName *directoryName = NULL; + char *which = NULL; + char *name = NULL; + SECStatus rv = SECSuccess; + SECItem *issuersAltName = NULL; + CERTCertificate *issuerCert = NULL; + void *mark = NULL; + + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + error_allocate(); + } + if (type == 0) { + which = make_copy_string("SubAltNameSelect0", 20,'\0'); + genName = MakeAltName(data, which, arena); + } else { + if (autoIssuer) { + autoIssuer = find_field_bool(data,"IssuerAltNameSourceRadio-auto", + PR_TRUE); + issuerCert = CERT_FindCertByNameString(handle, issuerNameStr); + rv = cert_FindExtension((*issuerCert).extensions, + SEC_OID_X509_SUBJECT_ALT_NAME, + issuersAltName); + if (issuersAltName == NULL) { + name = PORT_Alloc(PORT_Strlen((*issuerCert).subjectName) + 4); + PORT_Strcpy(name, (*issuerCert).subjectName); + PORT_Strcat(name, " - 5"); + } + } else { + which = make_copy_string("IssuerAltNameSelect0", 20,'\0'); + genName = MakeAltName(data, which, arena); + } + } + if (type == 0) { + EncodeAndAddExtensionValue(arena, extHandle, genName, + find_field_bool(data, "SubAltName-crit", + PR_TRUE), + SEC_OID_X509_SUBJECT_ALT_NAME, + (EXTEN_VALUE_ENCODER) + CERT_EncodeAltNameExtension); + + } else { + if (autoIssuer && (name == NULL)) { + rv = CERT_AddExtension + (extHandle, SEC_OID_X509_ISSUER_ALT_NAME, issuersAltName, + find_field_bool(data, "IssuerAltName-crit", PR_TRUE), PR_TRUE); + } else { + EncodeAndAddExtensionValue(arena, extHandle, genName, + find_field_bool(data, + "IssuerAltName-crit", + PR_TRUE), + SEC_OID_X509_ISSUER_ALT_NAME, + (EXTEN_VALUE_ENCODER) + CERT_EncodeAltNameExtension); + } + } + if (which != NULL) { + PORT_Free(which); + } + if (issuerCert != NULL) { + CERT_DestroyCertificate(issuerCert); + } +#if 0 + if (arena != NULL) { + PORT_ArenaRelease (arena, mark); + } +#endif + return rv; +} + + +static SECStatus +AddNameConstraints(void *extHandle, + Pair *data) +{ + PRBool autoIssuer = PR_FALSE; + PRArenaPool *arena = NULL; + CERTNameConstraints *constraints = NULL; + char *constraint = NULL; + SECStatus rv = SECSuccess; + + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + error_allocate(); + } + constraints = MakeNameConstraints(data, arena); + if (constraints != NULL) { + EncodeAndAddExtensionValue(arena, extHandle, constraints, PR_TRUE, + SEC_OID_X509_NAME_CONSTRAINTS, + (EXTEN_VALUE_ENCODER) + CERT_EncodeNameConstraintsExtension); + } + if (arena != NULL) { + PORT_ArenaRelease (arena, NULL); + } + return rv; +} + + +static SECStatus +add_extensions(CERTCertificate *subjectCert, + Pair *data, + char *issuerNameStr, + CERTCertDBHandle *handle) +{ + void *extHandle; + SECStatus rv = SECSuccess; + + + extHandle = CERT_StartCertExtensions (subjectCert); + if (extHandle == NULL) { + error_out("ERROR: Unable to get certificates extension handle"); + } + if (find_field_bool(data, "keyUsage", PR_TRUE)) { + rv = AddKeyUsage(extHandle, data); + if (rv != SECSuccess) { + error_out("ERROR: Unable to add Key Usage extension"); + } + } + + if( find_field_bool(data, "extKeyUsage", PR_TRUE) ) { + rv = AddExtKeyUsage(extHandle, data); + if( SECSuccess != rv ) { + error_out("ERROR: Unable to add Extended Key Usage extension"); + } + } + + if (find_field_bool(data, "basicConstraints", PR_TRUE)) { + rv = AddBasicConstraint(extHandle, data); + if (rv != SECSuccess) { + error_out("ERROR: Unable to add Basic Constraint extension"); + } + } + if (find_field_bool(data, "subjectKeyIdentifier", PR_TRUE)) { + rv = AddSubKeyID(extHandle, data, subjectCert); + if (rv != SECSuccess) { + error_out("ERROR: Unable to add Subject Key Identifier Extension"); + } + } + if (find_field_bool(data, "authorityKeyIdentifier", PR_TRUE)) { + rv = AddAuthKeyID (extHandle, data, issuerNameStr, handle); + if (rv != SECSuccess) { + error_out("ERROR: Unable to add Authority Key Identifier extension"); + } + } + if (find_field_bool(data, "privKeyUsagePeriod", PR_TRUE)) { + rv = AddPrivKeyUsagePeriod (extHandle, data, subjectCert); + if (rv != SECSuccess) { + error_out("ERROR: Unable to add Private Key Usage Period extension"); + } + } + if (find_field_bool(data, "SubAltName", PR_TRUE)) { + rv = AddAltName (extHandle, data, NULL, NULL, 0); + if (rv != SECSuccess) { + error_out("ERROR: Unable to add Subject Alternative Name extension"); + } + } + if (find_field_bool(data, "IssuerAltName", PR_TRUE)) { + rv = AddAltName (extHandle, data, issuerNameStr, handle, 1); + if (rv != SECSuccess) { + error_out("ERROR: Unable to add Issuer Alternative Name Extension"); + } + } + if (find_field_bool(data, "NameConstraints", PR_TRUE)) { + rv = AddNameConstraints(extHandle, data); + if (rv != SECSuccess) { + error_out("ERROR: Unable to add Name Constraints Extension"); + } + } + if (find_field_bool(data, "netscape-cert-type", PR_TRUE)) { + rv = AddNscpCertType(extHandle, data); + if (rv != SECSuccess) { + error_out("ERROR: Unable to add Netscape Certificate Type Extension"); + } + } + if (find_field_bool(data, "netscape-base-url", PR_TRUE)) { + rv = add_IA5StringExtension(extHandle, + find_field(data, "netscape-base-url-text", + PR_TRUE), + find_field_bool(data, + "netscape-base-url-crit", + PR_TRUE), + SEC_OID_NS_CERT_EXT_BASE_URL); + if (rv != SECSuccess) { + error_out("ERROR: Unable to add Netscape Base URL Extension"); + } + } + if (find_field_bool(data, "netscape-revocation-url", PR_TRUE)) { + rv = add_IA5StringExtension(extHandle, + find_field(data, + "netscape-revocation-url-text", + PR_TRUE), + find_field_bool + (data, "netscape-revocation-url-crit", + PR_TRUE), + SEC_OID_NS_CERT_EXT_REVOCATION_URL); + if (rv != SECSuccess) { + error_out("ERROR: Unable to add Netscape Revocation URL Extension"); + } + } + if (find_field_bool(data, "netscape-ca-revocation-url", PR_TRUE)) { + rv = add_IA5StringExtension(extHandle, + find_field(data, + "netscape-ca-revocation-url-text", + PR_TRUE), + find_field_bool + (data, "netscape-ca-revocation-url-crit" + , PR_TRUE), + SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL); + if (rv != SECSuccess) { + error_out("ERROR: Unable to add Netscape CA Revocation URL Extension"); + } + } + if (find_field_bool(data, "netscape-cert-renewal-url", PR_TRUE)) { + rv = add_IA5StringExtension(extHandle, + find_field(data, + "netscape-cert-renewal-url-text", + PR_TRUE), + find_field_bool + (data, "netscape-cert-renewal-url-crit", + PR_TRUE), + SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL); + if (rv != SECSuccess) { + error_out("ERROR: Unable to add Netscape Certificate Renewal URL Extension"); + } + } + if (find_field_bool(data, "netscape-ca-policy-url", PR_TRUE)) { + rv = add_IA5StringExtension(extHandle, + find_field(data, + "netscape-ca-policy-url-text", + PR_TRUE), + find_field_bool + (data, "netscape-ca-policy-url-crit", + PR_TRUE), + SEC_OID_NS_CERT_EXT_CA_POLICY_URL); + if (rv != SECSuccess) { + error_out("ERROR: Unable to add Netscape CA Policy URL Extension"); + } + } + if (find_field_bool(data, "netscape-ssl-server-name", PR_TRUE)) { + rv = add_IA5StringExtension(extHandle, + find_field(data, + "netscape-ssl-server-name-text", + PR_TRUE), + find_field_bool + (data, "netscape-ssl-server-name-crit", + PR_TRUE), + SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME); + if (rv != SECSuccess) { + error_out("ERROR: Unable to add Netscape SSL Server Name Extension"); + } + } + if (find_field_bool(data, "netscape-comment", PR_TRUE)) { + rv = add_IA5StringExtension(extHandle, + find_field(data, "netscape-comment-text", + PR_TRUE), + find_field_bool(data, + "netscape-comment-crit", + PR_TRUE), + SEC_OID_NS_CERT_EXT_COMMENT); + if (rv != SECSuccess) { + error_out("ERROR: Unable to add Netscape Comment Extension"); + } + } + CERT_FinishExtensions(extHandle); + return (rv); +} + + + +char * +return_dbpasswd(PK11SlotInfo *slot, PRBool retry, void *data) +{ + char *rv; + + /* don't clobber our poor smart card */ + if (retry == PR_TRUE) { + return NULL; + } + rv = PORT_Alloc(4); + PORT_Strcpy(rv, "foo"); + return rv; +} + + +SECKEYPrivateKey * +FindPrivateKeyFromNameStr(char *name, + CERTCertDBHandle *certHandle) +{ + SECKEYPrivateKey *key; + CERTCertificate *cert; + CERTCertificate *p11Cert; + SECStatus status = SECSuccess; + + + /* We don't presently have a PK11 function to find a cert by + ** subject name. + ** We do have a function to find a cert in the internal slot's + ** cert db by subject name, but it doesn't setup the slot info. + ** So, this HACK works, but should be replaced as soon as we + ** have a function to search for certs accross slots by subject name. + */ + cert = CERT_FindCertByNameString(certHandle, name); + if (cert == NULL || cert->nickname == NULL) { + error_out("ERROR: Unable to retrieve issuers certificate"); + } + p11Cert = PK11_FindCertFromNickname(cert->nickname, NULL); + if (p11Cert == NULL) { + error_out("ERROR: Unable to retrieve issuers certificate"); + } + key = PK11_FindKeyByAnyCert(p11Cert, NULL); + return key; +} + +static SECItem * +SignCert(CERTCertificate *cert, + char *issuerNameStr, + Pair *data, + CERTCertDBHandle *handle, + int which_key) +{ + SECItem der; + SECItem *result = NULL; + SECKEYPrivateKey *caPrivateKey = NULL; + SECStatus rv; + PRArenaPool *arena; + SECOidTag algID; + + if (which_key == 0) { + caPrivateKey = FindPrivateKeyFromNameStr(issuerNameStr, handle); + } else { + caPrivateKey = privkeys[which_key - 1]; + } + if (caPrivateKey == NULL) { + error_out("ERROR: unable to retrieve issuers key"); + } + + arena = cert->arena; + + switch(caPrivateKey->keyType) { + case rsaKey: + algID = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; + break; + case dsaKey: + algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; + break; + default: + error_out("ERROR: Unknown key type for issuer."); + goto done; + break; + } + + rv = SECOID_SetAlgorithmID(arena, &cert->signature, algID, 0); + if (rv != SECSuccess) { + error_out("ERROR: Could not set signature algorithm id."); + } + + if (find_field_bool(data,"ver-1", PR_TRUE)) { + *(cert->version.data) = 0; + cert->version.len = 1; + } else { + *(cert->version.data) = 2; + cert->version.len = 1; + } + der.data = NULL; + der.len = 0; + (void) SEC_ASN1EncodeItem (arena, &der, cert, CERT_CertificateTemplate); + if (der.data == NULL) { + error_out("ERROR: Could not encode certificate.\n"); + } + rv = SEC_DerSignData (arena, &(cert->derCert), der.data, der.len, caPrivateKey, + algID); + if (rv != SECSuccess) { + error_out("ERROR: Could not sign encoded certificate data.\n"); + } +done: + SECKEY_DestroyPrivateKey(caPrivateKey); + return &(cert->derCert); +} + + +int +main(int argc, char **argv) +{ + int length = 500; + int remaining = 500; + int n; + int fields = 3; + int i; + int serial; + int chainLen; + int which_key; + char *pos; +#ifdef OFFLINE + char *form_output = "key=MIIBPTCBpzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA7SLqjWBL9Wl11Vlg%0AaMqZCvcQOL%2FnvSqYPPRP0XZy9SoAeyWzQnBOiCm2t8H5mK7r2jnKdAQOmfhjaJil%0A3hNVu3SekHOXF6Ze7bkWa6%2FSGVcY%2FojkydxFSgY43nd1iydzPQDp8WWLL%2BpVpt%2B%2B%0ATRhFtVXbF0fQI03j9h3BoTgP2lkCAwEAARYDZm9vMA0GCSqGSIb3DQEBBAUAA4GB%0AAJ8UfRKJ0GtG%2B%2BufCC6tAfTzKrq3CTBHnom55EyXcsAsv6WbDqI%2F0rLAPkn2Xo1r%0AnNhtMxIuj441blMt%2Fa3AGLOy5zmC7Qawt8IytvQikQ1XTpTBCXevytrmLjCmlURr%0ANJryTM48WaMQHiMiJpbXCqVJC1d%2FpEWBtqvALzZaOOIy&subject=CN%3D%22test%22%26serial-auto%3Dtrue%26serial_value%3D%26ver-1%3Dtrue%26ver-3%3Dfalse%26caChoiceradio-SignWithDefaultkey%3Dtrue%26caChoiceradio-SignWithRandomChain%3Dfalse%26autoCAs%3D%26caChoiceradio-SignWithSpecifiedChain%3Dfalse%26manCAs%3D%26%24"; +#else + char *form_output; +#endif + char *issuerNameStr; + char *certName; + char *DBdir = DB_DIRECTORY; + char *prefixs[10] = {"CA#1-", "CA#2-", "CA#3-", + "CA#4-", "CA#5-", "CA#6-", + "CA#7-", "CA#8-", "CA#9-", ""}; + Pair *form_data; + CERTCertificate *cert; + CERTCertDBHandle *handle; + CERTCertificateRequest *certReq = NULL; + int warpmonths = 0; + SECItem *certDER; +#ifdef FILEOUT + FILE *outfile; +#endif + SECStatus status = SECSuccess; + extern char prefix[PREFIX_LEN]; + SEC_PKCS7ContentInfo *certChain; + SECItem *encodedCertChain; + PRBool UChain = PR_FALSE; + + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + +#ifdef TEST + sleep(20); +#endif + SECU_ConfigDirectory(DBdir); + + PK11_SetPasswordFunc(return_dbpasswd); + status = NSS_InitReadWrite(DBdir); + if (status != SECSuccess) { + SECU_PrintPRandOSError(progName); + return -1; + } + handle = CERT_GetDefaultCertDB(); + + prefix[0]= '\0'; +#if !defined(OFFLINE) + form_output = (char*) PORT_Alloc(length); + if (form_output == NULL) { + error_allocate(); + } + pos = form_output; + while (feof(stdin) == 0 ) { + if (remaining <= 1) { + remaining += length; + length = length * 2; + form_output = PORT_Realloc(form_output, (length)); + if (form_output == NULL) { + error_allocate(); + } + pos = form_output + length - remaining; + } + n = fread(pos, 1, (size_t) (remaining - 1), stdin); + pos += n; + remaining -= n; + } + *pos = '&'; + pos++; + length = pos - form_output; +#else + length = PORT_Strlen(form_output); +#endif +#ifdef FILEOUT + printf("Content-type: text/plain\n\n"); + fwrite(form_output, 1, (size_t)length, stdout); + printf("\n"); +#endif +#ifdef FILEOUT + fwrite(form_output, 1, (size_t)length, stdout); + printf("\n"); + fflush(stdout); +#endif + form_data = make_datastruct(form_output, length); + status = clean_input(form_data); +#if !defined(OFFLINE) + PORT_Free(form_output); +#endif +#ifdef FILEOUT + i = 0; + while(return_name(form_data, i) != NULL) { + printf("%s",return_name(form_data,i)); + printf("=\n"); + printf("%s",return_data(form_data,i)); + printf("\n"); + i++; + } + printf("I got that done, woo hoo\n"); + fflush(stdout); +#endif + issuerNameStr = PORT_Alloc(200); + if (find_field_bool(form_data, "caChoiceradio-SignWithSpecifiedChain", + PR_FALSE)) { + UChain = PR_TRUE; + chainLen = atoi(find_field(form_data, "manCAs", PR_FALSE)); + PORT_Strcpy(prefix, prefixs[0]); + issuerNameStr = PORT_Strcpy(issuerNameStr, + "CN=Cert-O-Matic II, O=Cert-O-Matic II"); + if (chainLen == 0) { + UChain = PR_FALSE; + } + } else { + if (find_field_bool(form_data, "caChoiceradio-SignWithRandomChain", + PR_FALSE)) { + PORT_Strcpy(prefix,prefixs[9]); + chainLen = atoi(find_field(form_data, "autoCAs", PR_FALSE)); + if (chainLen < 1 || chainLen > 18) { + issuerNameStr = PORT_Strcpy(issuerNameStr, + "CN=CA18, O=Cert-O-Matic II"); + } + issuerNameStr = PORT_Strcpy(issuerNameStr, "CN=CA"); + issuerNameStr = PORT_Strcat(issuerNameStr, + find_field(form_data,"autoCAs", PR_FALSE)); + issuerNameStr = PORT_Strcat(issuerNameStr,", O=Cert-O-Matic II"); + } else { + issuerNameStr = PORT_Strcpy(issuerNameStr, + "CN=Cert-O-Matic II, O=Cert-O-Matic II"); + } + chainLen = 0; + } + + i = -1; + which_key = 0; + do { + extern SECStatus cert_GetKeyID(CERTCertificate *cert); + i++; + if (i != 0 && UChain) { + PORT_Strcpy(prefix, prefixs[i]); + } + /* find_field(form_data,"subject", PR_TRUE); */ + certReq = makeCertReq(form_data, which_key); +#ifdef OFFLINE + serial = 900; +#else + serial = get_serial_number(form_data); +#endif + cert = MakeV1Cert(handle, certReq, issuerNameStr, PR_FALSE, + serial, warpmonths, form_data); + if (certReq != NULL) { + CERT_DestroyCertificateRequest(certReq); + } + if (find_field_bool(form_data,"ver-3", PR_TRUE)) { + status = add_extensions(cert, form_data, issuerNameStr, handle); + if (status != SECSuccess) { + error_out("ERROR: Unable to add extensions"); + } + } + status = cert_GetKeyID(cert); + if (status == SECFailure) { + error_out("ERROR: Unable to get Key ID."); + } + certDER = SignCert(cert, issuerNameStr, form_data, handle, which_key); + CERT_NewTempCertificate(handle, certDER, NULL, PR_FALSE, PR_TRUE); + issuerNameStr = find_field(form_data, "subject", PR_TRUE); + /* SECITEM_FreeItem(certDER, PR_TRUE); */ + CERT_DestroyCertificate(cert); + if (i == (chainLen - 1)) { + i = 8; + } + ++which_key; + } while (i < 9 && UChain); + + + +#ifdef FILEOUT + outfile = fopen("../certout", "wb"); +#endif + certName = find_field(form_data, "subject", PR_FALSE); + cert = CERT_FindCertByNameString(handle, certName); + certChain = SEC_PKCS7CreateCertsOnly (cert, PR_TRUE, handle); + if (certChain == NULL) { + error_out("ERROR: No certificates in cert chain"); + } + encodedCertChain = SEC_PKCS7EncodeItem (NULL, NULL, certChain, NULL, NULL, + NULL); + if (encodedCertChain) { +#if !defined(FILEOUT) + printf("Content-type: application/x-x509-user-cert\r\n"); + printf("Content-length: %d\r\n\r\n", encodedCertChain->len); + fwrite (encodedCertChain->data, 1, encodedCertChain->len, stdout); +#else + fwrite (encodedCertChain->data, 1, encodedCertChain->len, outfile); +#endif + + } else { + error_out("Error: Unable to DER encode certificate"); + } +#ifdef FILEOUT + printf("\nI got here!\n"); + fflush(outfile); + fclose(outfile); +#endif + fflush(stdout); + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + return 0; +} + diff --git a/security/nss/cmd/certcgi/index.html b/security/nss/cmd/certcgi/index.html new file mode 100644 index 000000000..0bd79f3ce --- /dev/null +++ b/security/nss/cmd/certcgi/index.html @@ -0,0 +1,956 @@ +<HTML> <!-- -*- Mode: Java; tab-width: 8 -*- --> +<!-- + - The contents of this file are subject to the Mozilla Public + - License Version 1.1 (the "License"); you may not use this file + - except in compliance with the License. You may obtain a copy of + - the License at http://www.mozilla.org/MPL/ + - + - Software distributed under the License is distributed on an "AS + - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + - implied. See the License for the specific language governing + - rights and limitations under 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. + --> +<HEAD> +<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> +<SCRIPT LANGUAGE="JavaScript1.2"> + +script_url = 'http://interzone.mcom.com/cgi-bin/certomatic/bin/certcgi.cgi' + +ext_page_ver1 = + make_page_intro('Version 1 extensions', "#FFFFFF") + + '<layer ID="ext1">' + + 'Version 1 X.509 certs do not support extensions' + + '</layer>' + + '</body></html>'; + +cur_page = 1; + +num_ca = 0; + +index_list = + '0, your_certificate_index_label,' + + '0, netscape_extensions_index_label,' + + '0, standard_extensions_index_label,' + + '0, certifying_authorities_index_label'; + +var main_page = + make_page_intro('Your Key', "#FFFFFF") + + '<layer ID="main" SRC="main.html">' + + '</layer>' + + '</body></html>' ; + +add_index_list = ''; + +max_pages = 13; + +ver = 3 + +ext_page_array = new Array(max_pages); + +index_label = 'Options'; + +your_certificate_index_label = 'Your Certificate'; + +netscape_extensions_index_label = 'Netscape X.509 Extensions'; + +standard_extensions_index_label = 'Standard X.509 Extensions'; + +certifying_authorities_index_label = 'Certifying Authorities'; + +add_sub_alt_name_index_label = 'Add Subject Alternative Name'; + +function setSubAltNameType(form) +{ + with(form) + { + if (SubAltNameRadio[0].checked) + { + return true; + } + if (SubAltNameRadio[3].checked || SubAltNameRadio[5].checked) + { + SubAltNameDataType.checked = true; + return true; + } + if (SubAltNameRadio[1].checked || SubAltNameRadio[2].checked || + SubAltNameRadio[4].checked || SubAltNameRadio[6].checked || + SubAltNameRadio[7].checked || SubAltNameRadio[8].checked) + { + SubAltNameDataType.checked = false; + return true; + } + } + return true; +} + +function setIssuerAltNameType(form) +{ + with(form) + { + if (IssuerAltNameRadio[0].checked) + { + return true; + } + if (IssuerAltNameRadio[3].checked || IssuerAltNameRadio[5].checked) + { + IssuerAltNameDataType.checked = true; + return true; + } + if (IssuerAltNameRadio[1].checked || IssuerAltNameRadio[2].checked || + IssuerAltNameRadio[4].checked || IssuerAltNameRadio[6].checked || + IssuerAltNameRadio[7].checked || IssuerAltNameRadio[8].checked) + { + IssuerAltNameDataType.checked = false; + return true; + } + } + return true; +} + + +function setNameConstraintNameType(form) +{ + with(form) + { + if (NameConstraintRadio[0].checked) + { + return true; + } + if (NameConstraintRadio[3].checked || NameConstraintRadio[5].checked) + { + NameConstraintNameDataType.checked = true; + return true; + } + if (NameConstraintRadio[1].checked || NameConstraintRadio[2].checked || + NameConstraintRadio[4].checked || NameConstraintRadio[6].checked || + NameConstraintRadio[7].checked || NameConstraintRadio[8].checked) + { + NameConstraintNameDataType.checked = false; + return true; + } + } + return true; +} + + +function addSubAltName(form) +{ + + with(form) + { + var len = SubAltNameSelect.length; + var value; + var i = 0; + while(!(i == (SubAltNameRadio.length - 1)) & !(SubAltNameRadio[i].checked == true)) + { + i++; + } + if (i != 0) + { + value = SubAltNameText.value + " - " + (i + 1); + } + else + { + value = SubAltNameText.value + " - " + SubAltNameOtherNameOID.value + " - "; + if (SubAltNameDataType.checked) + { + value += "1 - "; + } + else + { + value += "0 - "; + } + value += (i + 1); + if (SubAltNameOtherNameOID.value == "") + { + alert("Other names must include an OID"); + return false; + } + } + + if ((SubAltNameText.value == "") | (SubAltNameRadio[i].checked != true)) + { + alert("Alternative Names must include values for name and name type."); + } + else + { + SubAltNameSelect.options[len] = new Option(value, value); + } + } + return true; +} + +function deleteSubAltName(form) +{ + with(form) + { + while (SubAltNameSelect.selectedIndex >= 0) + { + SubAltNameSelect[SubAltNameSelect.selectedIndex] = null; + } + } +} + +function addIssuerAltName(form) +{ + with(form) + { + var len = IssuerAltNameSelect.length; + var value; + var i = 0; + + while(!(i == (IssuerAltNameRadio.length -1)) & !(IssuerAltNameRadio[i].checked == true)) + { + i++; + } + if (i != 0) + { + value = IssuerAltNameText.value + " - " + (i + 1); + } + else + { + value = IssuerAltNameText.value + " - " + IssuerAltNameOtherNameOID.value + " - "; + if (IssuerAltNameDataType.checked) + { + value += "1 - "; + } + else + { + value += "0 - "; + } + value += (i + 1); + if (IssuerAltNameOtherNameOID.value == "") + { + alert("Other names must include an OID"); + return false; + } + } + if ((IssuerAltNameText.value == "") | (IssuerAltNameRadio[i].checked != true)) + { + alert("Alternative Names must include values for name and name type.") + } + else + { + IssuerAltNameSelect.options[len] = new Option(value, value); + } + } + return true; +} + +function deleteIssuerAltName(form) +{ + with(form) + { + while (IssuerAltNameSelect.selectedIndex >= 0) + { + IssuerAltNameSelect[IssuerAltNameSelect.selectedIndex] = null; + } + } +} + + + +function addNameConstraint(form) +{ + with(form) + { + var len = NameConstraintSelect.length; + var value; + var i = 0; + var min = NameConstraintMin.value; + var max = NameConstraintMax.value; + + while(!(i == (NameConstraintRadio.length - 1) ) & !(NameConstraintRadio[i].checked == true)) + { + i++; + } + value = NameConstraintText.value + " - "; + if (i == 0) + { + value += NameConstraintOtherNameOID.value + " - "; + if (NameConstraintNameDataType.checked) + { + value += "1 - "; + } + else + { + value += "0 - "; + } + if (NameConstraintOtherNameOID.value == "") + { + alert("Other names must include an OID"); + return false; + } + } + value += (i + 1) + " - "; + if (NameConstraintTypeRadio[0].checked == true) + { + value += "p - "; + } + else + { + value += "e - "; + } + value += min + " - " + max; + if ((min == "") | (NameConstraintText.value == "") | (NameConstraintRadio[i].checked != true)) + { + alert("Name Constraints must include values for minimum, name, and name type.") + } + else + { + NameConstraintSelect.options[len] = new Option(value, value); + } + } + return true; +} + +function deleteNameConstraint(form) +{ + with(form) + { + while (NameConstraintSelect.selectedIndex >= 0) + { + NameConstraintSelect[NameConstraintSelect.selectedIndex] = null; + } + } +} + + +function submit_it() +{ + save_cur_page(cur_page); + + var array_string; + var subject = ext_page_array[0][22][0]; + var serial = ext_page_array[0][10][0]; + var ver1 = (ver == 1); + var ver3 = (ver == 3); + var serial_number = ext_page_array[0][12][0]; + var notBefore = ext_page_array[0][20][0]; + var notAfter = ext_page_array[0][21][0]; + var manValidity = ext_page_array[0][19][0]; + + if (subject == "") + { + alert("The DN field must contain some data"); + return false; + } + if (!serial & serial_number == "") + { + alert("No serial number specified"); + return false; + } + if (ext_page_array[0][15][0]) + { + var keygen = "<keygen name=\"key\" challenge=\"foo\">"; + } + else + { + switch (ext_page_array[0][17][0]) { + case 2: + var keygen = "<keygen keytype=\"dsa\" pqg=\"MIGdAkEAjfKklEkidqo9JXWbsGhpy+rA2Dr7jQz3y7gyTw14guXQdi/FtyEOr8Lprawyq3qsSWk9+/g3JMLsBzbuMcgCkQIVAMdzIYxzfsjumTtPLe0w9I7azpFfAkEAYm0CeDnqChNBMWOlW0y1ACmdVSKVbO/LO/8Q85nOLC5xy53l+iS6v1jlt5UhklycxC6fb0ZLCIzFcq9T5teIAg==\" name=\"key\" challenge=\"foo\">"; + break; + case 1: + var keygen = "<keygen keytype=\"dsa\" pqg=\"MIHaAmDCboVgX0+6pEeMlbwsasWDVBcJNHPKMzkq9kbCRK2U3k+tE15n+Dc2g3ZjDYr1um51e2iLC34/BwAAAAAAAAAAAAAAAAAAAAAAAAABbBhnlFN5Djmt0Mk8cdEBY5H8iPMCFMhUnFtbpjn3EyfH2DjVg3ALh7FtAmA2zWzhpeCwvOTjYnQorlXiv0WcnSiWmaC79CRYkFt5i+UEfRxwP1eNGJBVB1T+CPW6JGd4WhgsqtSf53pn5DEtv++O7lNfXyOhWhb3KaWHYIx8fuAXtioIWkWmpfEIVZA=\" name=\"key\" challenge=\"foo\">"; + break; + case 0: + var keygen = "<keygen keytype=\"dsa\" pqg=\"MIIBHAKBgId8SiiWrcdua5zbsBhPkKfFcnHBG7T/bQla7c6OixGjjmSSuq2fJLvMKa579CaxHxLZzZZXIHmAk9poRgWl2GUUkCJ68XSum8OQzDPXPsofcEdeANjw3mIAAAAAAAAAAAAAAAAAAAAAAAAIE+MkW5hguLIQqWvEVi9dMpbNu6OZAhTIA+y3TgyiwA0D8pt686ofaL1IOQKBgAiZQC6UCXztr2iXxJrAC+51gN5oX/R9Thilln9RGegsWnHrdxUOpcm5vAWp1LU8TOXtujE8kqkm3UxIRhUWQORe9IxLANAXmZJqkw9FEVHkxj6Cy9detwT2MyBzSwS6avsf7aLisgHmI/IHSeapJsQ3NQa3rikb6zRiqIV+TVa6\" name=\"key\" challenge=\"foo\">"; + break; + } + } + array_string = build_array_string(); + hiddens = "<input type=\"hidden\" name=\"subject\" value=\'" + subject + "\'> \n" + + "<input type=\"hidden\" name=\"serial-auto\" value=\"" + serial + "\"> \n" + + "<input type=\"hidden\" name=\"serial_value\" value=\"" + serial_number + "\"> \n" + + "<input type=\"hidden\" name=\"ver-1\" value=\"" + ver1 + "\"> \n" + + "<input type=\"hidden\" name=\"ver-3\" value=\"" + ver3 + "\"> \n" + + "<input type=\"hidden\" name=\"notBefore\" value=\"" + notBefore + "\"> \n" + + "<input type=\"hidden\" name=\"notAfter\" value=\"" + notAfter + "\"> \n" + + "<input type=\"hidden\" name=\"manValidity\" value=\"" + manValidity + "\"> \n" + + array_string; + + var good_submit_page = + '<html>' + + '<BODY TEXT="#000000" LINK="#000000" VLINK="#000000" ALINK="#FF0000" BGCOLOR="#FFFFFF">' + + '<form method="post" action="' + script_url + '">' + + 'Select size for your key:' + keygen + '</p>' + + '<input type="submit"></p>' + + hiddens + + '</form>\n' + + '</body>\n' + + '</html>\n'; + + window.frames.extensions.document.write(good_submit_page); + window.frames.extensions.document.close(); + cur_page = max_pages + 1; + make_index(window); + return false; +} + + + +function build_array_string() +{ + var j; + var array_string = ''; + var pages; + + if ((ext_page_array[3][4][0] > 0) && ext_page_array[3][3][0]) + { + pages = 4 + parseInt(ext_page_array[3][4][0]); + } + else + { + pages = 4; + } + for (j = 1; j < pages; j++) + { + if ((j > 1 || (ver == 3)) && + (ext_page_array[j].length > 1)) + { + if (j < 4) + { + for (i = 0; i < ext_page_array[j].length; i++) + { + if (ext_page_array[j][i][3].indexOf("radio") == -1) + { + if (ext_page_array[j][i][3].indexOf("multiple") == -1) + { + array_string += '<input type=\"hidden\" name=\"' + ext_page_array[j][i][1] + '\" value=\'' + ext_page_array[j][i][0] + '\'> \n'; + } + else + { + for (k = 0; k < ext_page_array[j][i][0].length; k++) + { + array_string += '<input type=\"hidden\" name=\"' + ext_page_array[j][i][1] + k + '\" value=\'' + ext_page_array[j][i][0][k] + '\'> \n'; + } + } + } + else + { + array_string += '<input type=\"hidden\" name=\"' + ext_page_array[j][i][1] + '-' + ext_page_array[j][i][2] + '\" value=\'' + ext_page_array[j][i][0] + '\'> \n'; + } + } + } + else + { + for (i = 0; i < ext_page_array[j].length; i++) + { + if (ext_page_array[j][i][3].indexOf("radio") == -1) + { + if (ext_page_array[j][i][3].indexOf("multiple") == -1) + { + array_string += '<input type=\"hidden\" name=\"' + 'CA#' + (j - 3) + '-' + ext_page_array[j][i][1] + '\" value=\'' + ext_page_array[j][i][0] +'\'> \n'; + } + else + { + for (k = 0; k < ext_page_array[j][i][0].length; k++) + { + array_string += '<input type=\"hidden\" name=\"' + 'CA#' + (j - 3) + '-' + ext_page_array[j][i][1] + k + '\" value=\'' + ext_page_array[j][i][0][k] + '\'> \n'; + } + } + } + else + { + array_string += '<input type=\"hidden\" name=\"' + 'CA#' + (j - 3) + '-' + ext_page_array[j][i][1] + '-' + ext_page_array[j][i][2] + '\" value=\'' + ext_page_array[j][i][0] + '\'> \n'; + } + } + } + } + } + return array_string; +} + + + +function init_ext_page_array() +{ + for (i = 0; i < max_pages; i++) + { + ext_page_array[i] = ''; + } +} + +function ca_num_change(n,ca_form) +{ + with(ca_form) + { + n = parseInt(n,10); + if (caChoiceradio[2].checked) + { + if (n) + { + update_index(n); + } + else + { + update_index(0); + } + } + } +} + +function choice_change(ca_form) +{ + with(ca_form) + { + if (caChoiceradio[2].checked) + { + ca_num_change(manCAs.value,ca_form); + } + else + { + update_index(0); + } + } +} + +function update_index(n) +{ + var add_string = ''; + for (var i = 0; i < n; i++) + { + var j = i + 1; + add_string = add_string + ',1, \'CA #' + j + '\''; + } + top.add_index_list = add_string; + num_ca = n; + make_index(window); +} + +function set_ver1() +// redraws the extensions page for version 1 certificates +{ + ver = 1 + if (cur_page == 2 || cur_page == 3) + { + sa_switch_pane(window, cur_page, cur_page); + } +} + + +function set_ver3() +// redraws the extensions page for version 3 certificates +{ + ver = 3 + if (cur_page == 2) + { + sa_switch_pane(window, 0, 2); + } + else if (cur_page == 3) + { + sa_switch_pane(window, 0, 3); + } +} + +function reset_subject(marker, value, form) +// Updates the subject field from a subordinate field +{ + with(form) + { + var field_sep = '", '; + var begin_index = subject.value.indexOf(marker); + if (begin_index != 0 && subject.value[begin_index - 1] != ' ') + { + begin_index = subject.value.indexOf(marker, begin_index +1); + } + var end_index = subject.value.indexOf(field_sep, begin_index); + if (begin_index > -1) // is it a delete/change? + { + if (end_index == -1) // is it the last one (includes only one)? + { + if (value.length > 0) // do I have to change it? + { + if (begin_index == 0) // is is the only one? + { + subject.value = marker + '"' + value + '"'; + } + else // it is the last of many + { + subject.value = subject.value.substring(0,begin_index) + marker + '"' + value + '"'; + } + } + else // must be a delete + { + if (begin_index == 0) // is it the only one? + { + begin_index += 2; + } + subject.value = subject.value.substring(0,(begin_index - 2)); + } + } + else // it is the first of many or a middle one + { + if (value.length >0) // do I have to change it? + { + subject.value = subject.value.substring(0,(begin_index + marker.length + 1)) + value + subject.value.substring(end_index,subject.length); + } + else // it is a delete + { + subject.value = subject.value.substring(0,begin_index) + subject.value.substring((end_index + 3),subject.length); + } + } + } + else // It is either an insert or a do nothing + { + if (value.length > 0) // is it an insert? + { + if (subject.value.length == 0) // is subject currently empty? + { + subject.value = marker + '"' + value + '"'; + } + else + { + subject.value = subject.value + ', ' + marker + '"' + value + '"'; + } + } + } + } +} + + + +function reset_subjectFields(form) +// updates all the subordinate fields from the subject field of a form +// ************ move the strings to global variables, to make maintentance easier **************** +{ + + update_subject_Field(form, 'CN=\"', form.name); + update_subject_Field(form, 'MAIL=\"', form.email); + update_subject_Field(form, 'O=\"', form.org); + update_subject_Field(form, 'C=\"', form.country); + update_subject_Field(form, ' L=\"', form.loc); + update_subject_Field(form, 'ST=\"', form.state); + update_subject_Field(form, 'E=\"', form.email); + update_subject_Field(form, 'OU=\"', form.org_unit); + update_subject_Field(form, 'UID=\"', form.uid); +} + +function update_subject_Field(form, marker, update_field) +//updates a single subordinate field from the subject field of a form +// *************** need to deal with the two types of e-mail addresses ************** +{ + with(form) + { + var field_sep = '", '; + var begin_index = subject.value.indexOf(marker) + marker.length; + var end_index = subject.value.indexOf(field_sep, begin_index); + if (end_index == -1) + { + end_index = subject.value.indexOf('"',begin_index); + } + if (begin_index != (-1 + marker.length) ) + { + update_field.value = subject.value.substring(begin_index, end_index); + } + else + { + update_field.value = ''; + } + } +} + + +function switch_mail(form) + // *************** I need to figure out if I want to delete the other type of e-mail address ************ +{ + if (form.email_type[0].checked) + { + var del = 'E='; + var ins = 'MAIL='; + } + else + { + var del = 'MAIL='; + var ins = 'E='; + } + reset_subject(del, '', form); + reset_subject(ins, form.email.value, form); +} + +function make_page_intro(title, bgcolor) +{ + var style = '<STYLE TYPE="text/css">BODY{' + + 'font-family: Geneva,MS Sans Serif,Arial,Lucida,Helvetica,sans-serif;' + + 'font-size: 10pt;' + + '}' + + 'TD{' + + 'font-family: Geneva,MS Sans Serif,Arial,Lucida,Helvetica,sans-serif;' + + 'font-size: 10pt;}' + + '</STYLE>'; + + if (bgcolor == null) { bgcolor = "#C0C0C0"; } + return '<HTML><HEAD>' + + '<TITLE>' + title + '</TITLE>' + + '</HEAD>' + + '<BODY TEXT="#000000" LINK="#000000" VLINK="#000000" ALINK="#FF0000" ' + + 'BGCOLOR="' + bgcolor + '">'; +} + + +function make_index(window) +{ + with (window.frames.index) + { + eval ('index_string = make_index_page(cur_page, ' + index_list + add_index_list + ' )'); + fool1 = make_page_intro(index_label, "#FFFFFF") + + index_string + '</BODY></HTML>'; + document.write(fool1); + document.close(); + } +} + + +function save_cur_page(page_number) +{ + var len; + var j = page_number - 1; + if (frames.extensions.document.layers.length != 0) + { + with (frames.extensions.document.layers[0].document) + { + if ((page_number != 2 && page_number != 3 && page_number <= max_pages) || + ver == 3) + { + ext_page_array[j] = new Array(forms[0].elements.length); + for (i = 0; i < forms[0].elements.length; i++) + { + ext_page_array[j][i] = new Array(4); + switch (forms[0].elements[i].type) + { + case 'radio': case 'checkbox': + ext_page_array[j][i][0] = forms[0].elements[i].checked; + break; + case 'select-one': + ext_page_array[j][i][0] = forms[0].elements[i].selectedIndex; + break; + case 'select-multiple': + len = forms[0].elements[i].options.length; + ext_page_array[j][i][0] = new Array(len); + for(k = 0; k < len; k++) + { + ext_page_array[j][i][0][k] = forms[0].elements[i].options[k].value; + } + break; + default: + ext_page_array[j][i][0] = forms[0].elements[i].value; + } + ext_page_array[j][i][1] = forms[0].elements[i].name; + ext_page_array[j][i][2] = forms[0].elements[i].value; + ext_page_array[j][i][3] = forms[0].elements[i].type; + } + } + } + } +} + +function reload_form(page_number) +{ + var j = page_number - 1; + with (frames.extensions.document.layers[0].document) + { + if (((page_number < 2 || page_number > 3) || ver == 3) + && page_number != 0 && (ext_page_array[j].length > 1)) + { + for (i = 0; i < ext_page_array[j].length; i++) + { + switch (forms[0].elements[i].type) + { + case 'radio': case 'checkbox': + forms[0].elements[i].checked = ext_page_array[j][i][0]; + break; + case 'select-one': + forms[0].elements[i].selectedIndex = ext_page_array[j][i][0]; + break; + case 'select-multiple': + for (k = 0; k < ext_page_array[j][i][0].length; k++) + { + forms[0].elements[i].options[k] = new Option(ext_page_array[j][i][0][k], + ext_page_array[j][i][0][k]); + } + break; + default: + forms[0].elements[i].value = ext_page_array[j][i][0]; + } + } + } + } +} + +function sa_switch_pane(top_window, old_pane, new_pane) +{ + var ext_page_stnd = + make_page_intro(standard_extensions_index_label, "#FFFFFF") + + '<layer ID="ext" SRC="stnd_ext_form.html">' + + '</layer>' + + '</body></html>'; + + var ext_page_nscp = + make_page_intro(netscape_extensions_index_label, "#FFFFFF") + + '<layer ID="ext" SRC="nscp_ext_form.html">' + + '</layer>' + + '</body></html>'; + + var ext_page_ca = + make_page_intro(certifying_authorities_index_label, "#FFFFFF") + + '<layer ID="ext" SRC="ca.html">' + + '</layer>' + + '</body</html>'; + + var ext_page_ca_exp = + make_page_intro('Certifying Authority Details', "#FFFFFF") + + '<layer ID="ext" SRC="ca_form.html">' + + '</layer>' + + '</body></html>'; + + + if (old_pane > 0 && cur_page <= max_pages) + { + save_cur_page(old_pane); + } + cur_page = new_pane; + make_index(top_window); + if (new_pane == 2 || new_pane == 3) + { + if (ver == 1) + { + frames.extensions.document.write(ext_page_ver1); + frames.extensions.document.close(); + } + else + { + if (new_pane == 2) + { + frames.extensions.document.write(ext_page_nscp); + frames.extensions.document.close(); + reload_form(new_pane); + } + else + { + frames.extensions.document.write(ext_page_stnd); + frames.extensions.document.close(); + reload_form(new_pane); + } + } + } + else + { + if (new_pane == 4) + { + frames.extensions.document.write(ext_page_ca); + frames.extensions.document.close(); + reload_form(new_pane); + } + else + { + if (new_pane == 1) + { + frames.extensions.document.write(main_page); + frames.extensions.document.close(); + reload_form(new_pane); + } + else + { + frames.extensions.document.write(ext_page_ca_exp); + frames.extensions.document.close(); + reload_form(new_pane); + } + } + } +} + +function make_index_page(selected) +{ + var n_strings = ( make_index_page.arguments.length - 1 ) / 2; + var table_background; + var command; + var indent; + var label; + var ret_string = ""; + + ret_string += '<TABLE CELLSPACING=4>'; + for ( var i = 1; i <= n_strings; i++ ) { + if ( i == selected ) { + table_background = 'BGCOLOR=#BBCCBB'; + } else { + table_background = ''; + } + + indent = make_index_page.arguments[(i*2) - 1]; + label = make_index_page.arguments[(i*2)]; + + if ( indent == 0 ) { + ret_string += ('<TR><TD COLSPAN=2 ' + table_background + '>'); + } else { + ret_string += ('<TR><TD> </TD><TD ' + table_background + '>'); + } + + command = "'parent.sa_switch_pane(parent," + selected + "," + i + ")'"; + ret_string += ('<A HREF="javascript:void setTimeout(' + command + ',0)">'); + if ( indent == 0 ) { ret_string += "<B>"; } + ret_string += label; + if ( indent == 0 ) { ret_string += "</B>"; } + ret_string += '</A></TD></TR>'; + } + if (selected == (max_pages + 1)) + { + table_background = 'BGCOLOR=#BBCCBB'; + } else { + table_background = ''; + } + ret_string += + '<TR><TD COLSPAN=2 ' + table_background + + '><b><A HREF="javascript:void setTimeout(\'top.submit_it()\', 0)">Finish</A></b>' + + '</TD></TR>' + + '<input type="submit"></form>' + + '</TABLE>'; + return(ret_string); +} + + +function make_page(window) +// Draws the initial page setup +{ + selected = cur_page + init_ext_page_array() + + with (window.frames.extensions) { + document.write(main_page); + document.close(); + } + + make_index(window); + +} +</script> + +</HEAD> +<title>Cert-O-Matic</title> + <FRAMESET cols="150,*" BORDER=3 ONLOAD="make_page(window)"> + <FRAME SRC="about:blank" NAME="index" + MARGINWIDTH=15 MARGINHEIGHT=10 BORDER=3> + <FRAME SRC="about:blank" NAME="extensions" + MARGINWIDTH=15 MARGINHEIGHT=10 BORDER=3> + </FRAMESET> +</HTML> diff --git a/security/nss/cmd/certcgi/main.html b/security/nss/cmd/certcgi/main.html new file mode 100644 index 000000000..50e138aee --- /dev/null +++ b/security/nss/cmd/certcgi/main.html @@ -0,0 +1,105 @@ +<HTML> +<!-- + - The contents of this file are subject to the Mozilla Public + - License Version 1.1 (the "License"); you may not use this file + - except in compliance with the License. You may obtain a copy of + - the License at http://www.mozilla.org/MPL/ + - + - Software distributed under the License is distributed on an "AS + - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + - implied. See the License for the specific language governing + - rights and limitations under 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. + --> +<HEAD> + <TITLE>Main Layer for CertOMatic</TITLE> +</HEAD> + + <form method="post" name="primary_form" action="http://interzone.mcom.com/burp.cgi"> + <table border=0 cellspacing=10 cellpadding=0> + <tr> + <td> + Common Name:</td><td> <input type="text" name="name" onChange="{window.top.reset_subject('CN=', value, form)}"></p> + </td> + <td></td><td></td> + <td> + Organization: </td><td> <input type="text" name="org" onChange="{window.top.reset_subject('O=', value, form)}"></p></td> + <tr> + <td> + <input type="radio" name="email_type" value="1" onClick="window.top.switch_mail(form)">MAIL= + + <input type="radio" name="email_type" value="2" checked onClick="window.top.switch_mail(form)">E= + </td> + <td> + <input type="text" name="email" onChange="var temp;{if (email_type[0].checked) {temp = 'MAIL='} else {temp = 'E='}} ;{window.top.reset_subject(temp, value, form)}"> + </td> + <td></td><td></td><td> + Organizational Unit: </td><td><input type="text" name="org_unit" onChange="{window.top.reset_subject('OU=', value, form)}"></p></td> + <tr> + <td> + UID= </td><td><input type="text" name="uid" onChange="{window.top.reset_subject('UID=', value, form)}"></p></td> + <td></td><td></td><td> + Locality: </td><td><input type="text" name="loc" onChange="{window.top.reset_subject('L=', value, form)}"></p></td> + <tr> + <td> + State or Province: </td><td><input type="text" name="state" onChange="{window.top.reset_subject('ST=', value, form)}"></p></td> + <td></td><td></td><td> + Country: </td><td><input type="text" size="2" name="country" onChange="{window.top.reset_subject('C=', value, form)}" maxlength="2"></p></td> + <tr> + <td COLSPAN=2> + Serial Number: + <DD><input type="radio" name="serial" value="auto" checked> Auto Generate + <DD><input type="radio" name="serial" value="input"> + Use this hex value: <input type="text" name="serial_value" size="8" maxlength="8"></p> + </td> + <td></td> <td></td> + <td COLSPAN=2> + X.509 version: + <DD><input type="radio" name="ver" value="1" onClick="if (this.checked) {window.top.set_ver1();}"> Version 1 + <DD><input type="radio" name="ver" value="3" checked onClick="if (this.checked) {window.top.set_ver3();}"> Version 3</P></td> + <tr> + <td COLSPAN=2> + Key Type: + <DD><input type="radio" name="keyType" value="rsa" checked> RSA + <DD><input type="radio" name="keyType" value="dsa"> DSA</p> + Intermediate CA Key Sizes: + <DD><select name="keysize"> + <option>2048 (Very High Grade) + <option>1024 (High Grade) + <option>512 (Low Grade) + </select> + </td> + <td></td> <td></td> + <td COLSPAN=2> + Validity: + <DD><input type="radio" name="validity" value="auto" checked> + Generate Automatically + <DD><input type="radio" name="validity" value="man"> Use these values: + <DD>Not Before: <input type="text" size="15" maxlength="17" name="notBefore"> + <DD>Not After: <input type="text" size="15" maxlength="17" name="notAfter"> + <DD> + <FONT SIZE=-1><TT>YYMMDDhhmm[ss]{Z|+hhmm|-hhmm} </TT></FONT> + </table> + DN: <input type="text" name="subject" size="70" onChange="{window.top.reset_subjectFields(form)}"></P> + </form> +</HTML> diff --git a/security/nss/cmd/certcgi/manifest.mn b/security/nss/cmd/certcgi/manifest.mn new file mode 100644 index 000000000..9d659f821 --- /dev/null +++ b/security/nss/cmd/certcgi/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +# MODULE public and private header directories are implicitly REQUIREd. +MODULE = nss + +# This next line is used by .mk files +# and gets translated into $LINCS in manifest.mnw +REQUIRES = seccmd dbm + +DEFINES = -DNSPR20 + +CSRCS = certcgi.c + +PROGRAM = certcgi + +USE_STATIC_LIBS = 1 + diff --git a/security/nss/cmd/certcgi/nscp_ext_form.html b/security/nss/cmd/certcgi/nscp_ext_form.html new file mode 100644 index 000000000..de939eecb --- /dev/null +++ b/security/nss/cmd/certcgi/nscp_ext_form.html @@ -0,0 +1,113 @@ +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> +<html> +<!-- + - The contents of this file are subject to the Mozilla Public + - License Version 1.1 (the "License"); you may not use this file + - except in compliance with the License. You may obtain a copy of + - the License at http://www.mozilla.org/MPL/ + - + - Software distributed under the License is distributed on an "AS + - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + - implied. See the License for the specific language governing + - rights and limitations under 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. + --> + + <body> + <table border=1 cellspacing=5 cellpadding=5> + <form method="post" name="primary_form" action="http://interzone.mcom.com/burp.cgi"> + <tr> + <td> + <b>Netscape Certificate Type: </b></p> + Activate extension: <input type="checkbox" name="netscape-cert-type"></P> + Critical: <input type="checkbox" name="netscape-cert-type-crit"> + <td> + <input type="checkbox" name="netscape-cert-type-ssl-client"> SSL Client</P> + <input type="checkbox" name="netscape-cert-type-ssl-server"> SSL Server</P> + <input type="checkbox" name="netscape-cert-type-smime"> S/MIME</P> + <input type="checkbox" name="netscape-cert-type-object-signing"> Object Signing</P> + <input type="checkbox" name="netscape-cert-type-reserved"> Reserved for future use (bit 4)</P> + <input type="checkbox" name="netscape-cert-type-ssl-ca"> SSL CA</P> + <input type="checkbox" name="netscape-cert-type-smime-ca"> S/MIME CA</P> + <input type="checkbox" name="netscape-cert-type-object-signing-ca"> Object Signing CA</P> + </tr> + <tr> + <td> + <b>Netscape Base URL:</b></p> + Activate extension: <input type="checkbox" name="netscape-base-url"></P> + Critical: <input type="checkbox" name="netscape-base-url-crit"> + <td> + <input type="text" name="netscape-base-url-text" size="50"> + </tr> + <tr> + <td> + <b>Netscape Revocation URL:</b></p> + Activate extension: <input type="checkbox" name="netscape-revocation-url"></P> + Critical: <input type="checkbox" name="netscape-revocation-url-crit"> + <td> + <input type="text" name="netscape-revocation-url-text" size="50"> + </tr> + <tr> + <td> + <b>Netscape CA Revocation URL:</b></p> + Activate extension: <input type="checkbox" name="netscape-ca-revocation-url"></P> + Critical: <input type="checkbox" name="netscape-ca-revocation-url-crit"> + <td> + <input type="text" name="netscape-ca-revocation-url-text" size="50"> + </tr> + <tr> + <td> + <b>Netscape Certificate Renewal URL:</b></p> + Activate extension: <input type="checkbox" name="netscape-cert-renewal-url"></P> + Critical: <input type="checkbox" name="netscape-cert-renewal-url-crit"> + <td> + <input type="text" name="netscape-cert-renewal-url-text" size="50"> + </tr> + <tr> + <td> + <b>Netscape CA Policy URL:</b></p> + Activate extension: <input type="checkbox" name="netscape-ca-policy-url"></P> + Critical: <input type="checkbox" name="netscape-ca-policy-url-crit"> + <td> + <input type="text" name="netscape-ca-policy-url-text" size="50"> + </tr> + <tr> + <td> + <b>Netscape SSL Server Name:</b></p> + Activate extension: <input type="checkbox" name="netscape-ssl-server-name"></P> + Critical: <input type="checkbox" name="netscape-ssl-server-name-crit"> + <td> + <input type="text" name="netscape-ssl-server-name-text" size="50"> + </tr> + <tr> + <td> + <b>Netscape Comment:</b></p> + Activate extension: <input type="checkbox" name="netscape-comment"></P> + Critical: <input type="checkbox" name="netscape-comment-crit"> + <td> + <textarea name="netscape-comment-text" rows="5" cols="50"></textarea> + </tr> + + </table> + </body> +</html> diff --git a/security/nss/cmd/certcgi/stnd_ext_form.html b/security/nss/cmd/certcgi/stnd_ext_form.html new file mode 100644 index 000000000..ece9b2ff7 --- /dev/null +++ b/security/nss/cmd/certcgi/stnd_ext_form.html @@ -0,0 +1,247 @@ +<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> +<html> +<!-- + - The contents of this file are subject to the Mozilla Public + - License Version 1.1 (the "License"); you may not use this file + - except in compliance with the License. You may obtain a copy of + - the License at http://www.mozilla.org/MPL/ + - + - Software distributed under the License is distributed on an "AS + - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + - implied. See the License for the specific language governing + - rights and limitations under 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. + --> + + <body> + <table border=1 cellspacing=5 cellpadding=5> + <form method="post" name="primary_form" action="http://interzone.mcom.com/burp.cgi"> + <tr> + <td> + <b>Key Usage: </b></p> + Activate extension: <input type="checkbox" name="keyUsage"></P> + Critical: <input type="checkbox" name="keyUsage-crit"> + <td> + <input type="checkbox" name="keyUsage-digitalSignature"> Digital Signature</P> + <input type="checkbox" name="keyUsage-nonRepudiation"> Non Repudiation</P> + <input type="checkbox" name="keyUsage-keyEncipherment"> Key Encipherment</P> + <input type="checkbox" name="keyUsage-dataEncipherment"> Data Encipherment</P> + <input type="checkbox" name="keyUsage-keyAgreement"> Key Agreement</P> + <input type="checkbox" name="keyUsage-keyCertSign"> Key Certificate Signing</P> + <input type="checkbox" name="keyUsage-cRLSign"> CRL Signing</P> + </tr> + <tr> + <td> + <b>Extended Key Usage: </b></p> + Activate extension: <input type="checkbox" name="extKeyUsage"></P> + Critical: <input type="checkbox" name="extKeyUsage-crit"> + <td> + <input type="checkbox" name="extKeyUsage-serverAuth"> Server Auth</P> + <input type="checkbox" name="extKeyUsage-clientAuth"> Client Auth</P> + <input type="checkbox" name="extKeyUsage-codeSign"> Code Signing</P> + <input type="checkbox" name="extKeyUsage-emailProtect"> Email Protection</P> + <input type="checkbox" name="extKeyUsage-timeStamp"> Timestamp</P> + <input type="checkbox" name="extKeyUsage-ocspResponder"> OCSP Responder</P> + <input type="checkbox" name="extKeyUsage-NS-govtApproved"> Step-up</P> + </tr> + <tr> + <td> + <b>Basic Constraints:</b></p> + Activate extension: <input type="checkbox" name="basicConstraints"></P> + Critical: <input type="checkbox" name="basicConstraints-crit"> + <td> + CA:</p> + <dd><input type=radio name="basicConstraints-cA-radio" value="CA"> True</p> + <dd><input type=radio name="basicConstraints-cA-radio" value="NotCA"> False</p> + <input type="checkbox" name="basicConstraints-pathLengthConstraint"> + Include Path length: <input type="text" name="basicConstraints-pathLengthConstraint-text" size="2"></p> + </tr> + <tr> + <td> + <b>Authority Key Identifier:</b></p> + Activate extension: <input type="checkbox" name="authorityKeyIdentifier"> + <td> + <input type="radio" name="authorityKeyIdentifier-radio" value="keyIdentifier"> Key Identider</p> + <input type="radio" name="authorityKeyIdentifier-radio" value="authorityCertIssuer"> Issuer Name and Serial number</p> + </tr> + <tr> + <td> + <b>Subject Key Identifier:</b></p> + Activate extension: <input type="checkbox" name="subjectKeyIdentifier"> + <td> + Key Identifier: + <input type="text" name="subjectKeyIdentifier-text"></p> + This is an:<p> + <dd><dd><input type="radio" name="subjectKeyIdentifier-radio" value="ascii"> ascii text value<p> + <dd><dd><input type="radio" name="subjectKeyIdentifier-radio" value="hex"> hex value<p> + </tr> + <tr> + <td> + <b>Private Key Usage Period:</b></p> + Activate extension: <input type="checkbox" name="privKeyUsagePeriod"></p> + Critical: <input type="checkbox" name="privKeyUsagePeriod-crit"> + <td> + Use:</p> + <dd><input type="radio" name="privKeyUsagePeriod-radio" value="notBefore"> Not Before</p> + <dd><input type="radio" name="privKeyUsagePeriod-radio" value="notAfter"> Not After</p> + <dd><input type="radio" name="privKeyUsagePeriod-radio" value="both" > Both</p> + <b>Not to be used to sign before:</b></p> + <dd><input type="radio" name="privKeyUsagePeriod-notBefore-radio" value="auto"> Set to time of certificate issue</p> + <dd><input type="radio" name="privKeyUsagePeriod-notBefore-radio" value="manual"> Use This value</p> + <dd><dd>(YYYY/MM/DD HH:MM:SS): + <input type="text" name="privKeyUsagePeriod-notBefore-year" size="4" maxlength="4">/ + <input type="text" name="privKeyUsagePeriod-notBefore-month" size="2" maxlength="2">/ + <input type="text" name="privKeyUsagePeriod-notBefore-day" size="2" maxlength="2"> + <input type="text" name="privKeyUsagePeriod-notBefore-hour" size="2" maxlength="2">: + <input type="text" name="privKeyUsagePeriod-notBefore-minute" size="2" maxlength="2">: + <input type="text" name="privKeyUsagePeriod-notBefore-second" size="2" maxlength="2"></p> + <b>Not to be used to sign after:</b></p> + <dd>(YYYY/MM/DD HH:MM:SS): + <input type="text" name="privKeyUsagePeriod-notAfter-year" size="4" maxlength="4">/ + <input type="text" name="privKeyUsagePeriod-notAfter-month" size="2" maxlength="2">/ + <input type="text" name="privKeyUsagePeriod-notAfter-day" size="2" maxlength="2"> + <input type="text" name="privKeyUsagePeriod-notAfter-hour" size="2" maxlength="2">: + <input type="text" name="privKeyUsagePeriod-notAfter-minute" size="2" maxlength="2">: + <input type="text" name="privKeyUsagePeriod-notAfter-second" size="2" maxlength="2"></p> + </tr> + <tr> + <td> + <b>Subject Alternative Name:</b></p> + Activate extension: <input type="checkbox" name="SubAltName"></P> + Critical: <input type="checkbox" name="SubAltName-crit"> + <td> + <table> + <tr> + <td> + General Names:</p> + <select name="SubAltNameSelect" multiple size="10"> + </select></p></p> + <input type="button" name="SubAltName-add" value="Add" onClick="{parent.addSubAltName(this.form)}"> + <input type="button" name="SubAltName-delete" value="Delete" onClick="parent.deleteSubAltName(this.form)"> + </td><td> + <table><tr><td> + Name Type: </td></tr><tr><td> + <input type="radio" name="SubAltNameRadio" value="otherName" onClick="parent.setSubAltNameType(form)"> Other Name, + OID: <input type="text" name="SubAltNameOtherNameOID" size="6"> </td><td> + <input type="radio" name="SubAltNameRadio" value="rfc822Name" onClick="parent.setSubAltNameType(form)"> RFC 822 Name</td></tr><td> + <input type="radio" name="SubAltNameRadio" value="dnsName" onClick="parent.setSubAltNameType(form)"> DNS Name </td><td> + <input type="radio" name="SubAltNameRadio" value="x400" onClick="parent.setSubAltNameType(form)"> X400 Address</td></tr><td> + <input type="radio" name="SubAltNameRadio" value="directoryName" onClick="parent.setSubAltNameType(form)"> Directory Name</td><td> + <input type="radio" name="SubAltNameRadio" value="ediPartyName" onClick="parent.setSubAltNameType(form)"> EDI Party Name</td></tr><td> + <input type="radio" name="SubAltNameRadio" value="URL" onClick="parent.setSubAltNameType(form)"> Uniform Resource Locator</td><td> + <input type="radio" name="SubAltNameRadio" value="ipAddress" onClick="parent.setSubAltNameType(form)"> IP Address</td></tr><td> + <input type="radio" name="SubAltNameRadio" value="regID"onClick="parent.setSubAltNameType(form)"> Registered ID</td><td> + <input type="radio" name="SubAltNameRadio" value="nscpNickname" onClick="parent.setSubAltNameType(form)"> Netscape Certificate Nickname</td><td></tr> + </table> + Name: <input type="text" name="SubAltNameText"> + Binary Encoded: <input type="checkbox" name="SubAltNameDataType" value="binary" onClick="parent.setSubAltNameType(form)"></p> + </tr> + </table> + </tr> + + + <tr> + <td> + <b>Issuer Alternative Name:</b></p> + Activate extension: <input type="checkbox" name="IssuerAltName"></P> + Critical: <input type="checkbox" name="IssuerAltName-crit"> + <td> + <input type="radio" name="IssuerAltNameSourceRadio" value="auto"> Use the Subject Alternative Name from the Issuers Certificate</p> + <input type="radio" name="IssuerAltNameSourceRadio" value="man"> Use this Name: + <table> + <tr> + <td> + General Names:</p> + <select name="IssuerAltNameSelect" multiple size="10"> + </select></p></p> + <input type="button" name="IssuerAltName-add" value="Add" onClick="{parent.addIssuerAltName(this.form)}"> + <input type="button" name="IssuerAltName-delete" value="Delete" onClick="parent.deleteIssuerAltName(this.form)"> + </td><td> + <table><tr><td> + Name Type: </td></tr><tr><td> + <input type="radio" name="IssuerAltNameRadio" value="otherName" onClick="parent.setIssuerAltNameType(form)"> Other Name, + OID: <input type="text" name="IssuerAltNameOtherNameOID" size="6"> </td><td> + <input type="radio" name="IssuerAltNameRadio" value="rfc822Name" onClick="parent.setIssuerAltNameType(form)"> RFC 822 Name</td></tr><td> + <input type="radio" name="IssuerAltNameRadio" value="dnsName" onClick="parent.setIssuerAltNameType(form)"> DNS Name </td><td> + <input type="radio" name="IssuerAltNameRadio" value="x400" onClick="parent.setIssuerAltNameType(form)"> X400 Address</td></tr><td> + <input type="radio" name="IssuerAltNameRadio" value="directoryName" onClick="parent.setIssuerAltNameType(form)"> Directory Name</td><td> + <input type="radio" name="IssuerAltNameRadio" value="ediPartyName" onClick="parent.setIssuerAltNameType(form)"> EDI Party Name</td></tr><td> + <input type="radio" name="IssuerAltNameRadio" value="URL" onClick="parent.setIssuerAltNameType(form)"> Uniform Resource Locator</td><td> + <input type="radio" name="IssuerAltNameRadio" value="ipAddress" onClick="parent.setIssuerAltNameType(form)"> IP Address</td></tr><td> + <input type="radio" name="IssuerAltNameRadio" value="regID" onClick="parent.setIssuerAltNameType(form)"> Registered ID</td><td></tr> + </table> + Name: <input type="text" name="IssuerAltNameText"> + Binary Encoded: <input type="checkbox" name="IssuerAltNameDataType" value="binary" onClick="parent.setIssuerAltNameType(form)"></p> + </tr> + </table> + </tr> + + <tr> + <td> + <b>Name Constraints:</b></p> + Activate extension: <input type="checkbox" name="NameConstraints"></P> + <td> + <table> + <tr> + <td> + Name Constraints:</p> + <select name="NameConstraintSelect" multiple size="10"> + </select></p></p> + <input type="button" name="NameConstraint-add" value="Add" onClick="{parent.addNameConstraint(this.form)}"> + <input type="button" name="NameConstraint-delete" value="Delete" onClick="parent.deleteNameConstraint(this.form)"> + </td><td> + <table><tr><td> + Name Type: </td></tr><tr><td> + <input type="radio" name="NameConstraintRadio" value="otherName" onClick="parent.setNameConstraintNameType(form)"> Other Name, + OID: <input type="text" name="NameConstraintOtherNameOID" size="6"> </td><td> + <input type="radio" name="NameConstraintRadio" value="rfc822Name" onClick="parent.setNameConstraintNameType(form)"> RFC 822 Name</td></tr><td> + <input type="radio" name="NameConstraintRadio" value="dnsName" onClick="parent.setNameConstraintNameType(form)"> DNS Name </td><td> + <input type="radio" name="NameConstraintRadio" value="x400" onClick="parent.setNameConstraintNameType(form)"> X400 Address</td></tr><td> + <input type="radio" name="NameConstraintRadio" value="directoryName" onClick="parent.setNameConstraintNameType(form)"> Directory Name</td><td> + <input type="radio" name="NameConstraintRadio" value="ediPartyName" onClick="parent.setNameConstraintNameType(form)"> EDI Party Name</td></tr><td> + <input type="radio" name="NameConstraintRadio" value="URL" onClick="parent.setNameConstraintNameType(form)"> Uniform Resource Locator</td><td> + <input type="radio" name="NameConstraintRadio" value="ipAddress" onClick="parent.setNameConstraintNameType(form)"> IP Address</td></tr><td> + <input type="radio" name="NameConstraintRadio" value="regID" onClick="parent.setNameConstraintNameType(form)"> Registered ID</td><td></tr> + </table> + Name: <input type="text" name="NameConstraintText"> + Binary Encoded: <input type="checkbox" name="NameConstraintNameDataType" value="binary" onClick="parent.setNameConstraintNameType(form)"></p> + Constraint type:<p> + <dd><input type="radio" name="NameConstraintTypeRadio" value="permited"> permited<p> + <dd><input type="radio" name="NameConstraintTypeRadio" value="excluded"> excluded<p> + Minimum: <input type="text" name="NameConstraintMin" size="8" maxlength="8"></p> + Maximum: <input type="text" name="NameConstraintMax" size="8" maxlength="8"></p> + </tr> + </table> + </tr> + + </table> + </body> +</html> + + + + + + + + diff --git a/security/nss/cmd/certutil/Makefile b/security/nss/cmd/certutil/Makefile new file mode 100644 index 000000000..8650a607d --- /dev/null +++ b/security/nss/cmd/certutil/Makefile @@ -0,0 +1,76 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/certutil/certutil.c b/security/nss/cmd/certutil/certutil.c new file mode 100644 index 000000000..0ef9710e2 --- /dev/null +++ b/security/nss/cmd/certutil/certutil.c @@ -0,0 +1,2885 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* +** certutil.c +** +** utility for managing certificates and the cert database +** +*/ +#include <stdio.h> +#include <string.h> + +#if defined(WIN32) +#include "fcntl.h" +#include "io.h" +#endif + +#include "secutil.h" + +#if defined(XP_UNIX) +#include <unistd.h> +#endif + +#include "nspr.h" +#include "prtypes.h" +#include "prtime.h" +#include "prlong.h" + +#include "pk11func.h" +#include "secasn1.h" +#include "cert.h" +#include "cryptohi.h" +#include "secoid.h" +#include "certdb.h" +#include "nss.h" + +#define MIN_KEY_BITS 512 +#define MAX_KEY_BITS 2048 +#define DEFAULT_KEY_BITS 1024 + +#define GEN_BREAK(e) rv=e; break; + + +extern SECKEYPrivateKey *CERTUTIL_GeneratePrivateKey(KeyType keytype, + PK11SlotInfo *slot, + int rsasize, + int publicExponent, + char *noise, + SECKEYPublicKey **pubkeyp, + char *pqgFile, + secuPWData *pwdata); + +static char *progName; + +static CERTGeneralName * +GetGeneralName (PRArenaPool *arena) +{ + CERTGeneralName *namesList = NULL; + CERTGeneralName *current; + CERTGeneralName *tail = NULL; + SECStatus rv = SECSuccess; + int intValue; + char buffer[512]; + void *mark; + + PORT_Assert (arena); + mark = PORT_ArenaMark (arena); + do { + puts ("\nSelect one of the following general name type: \n"); + puts ("\t1 - instance of other name\n\t2 - rfc822Name\n\t3 - dnsName\n"); + puts ("\t4 - x400Address\n\t5 - directoryName\n\t6 - ediPartyName\n"); + puts ("\t7 - uniformResourceidentifier\n\t8 - ipAddress\n\t9 - registerID\n"); + puts ("\tOther - omit\n\t\tChoice:"); + scanf ("%d", &intValue); + if (intValue >= certOtherName || intValue <= certRegisterID) { + if (namesList == NULL) { + namesList = current = tail = (CERTGeneralName *) PORT_ArenaAlloc + (arena, sizeof (CERTGeneralName)); + } else { + current = (CERTGeneralName *) PORT_ArenaAlloc(arena, + sizeof (CERTGeneralName)); + } + if (current == NULL) { + GEN_BREAK (SECFailure); + } + } else { + break; + } + current->type = intValue; + puts ("\nEnter data:"); + fflush (stdout); + gets (buffer); + switch (current->type) { + case certURI: + case certDNSName: + case certRFC822Name: + current->name.other.data = PORT_ArenaAlloc (arena, strlen (buffer)); + if (current->name.other.data == NULL) { + GEN_BREAK (SECFailure); + } + PORT_Memcpy + (current->name.other.data, buffer, current->name.other.len = strlen(buffer)); + break; + + case certEDIPartyName: + case certIPAddress: + case certOtherName: + case certRegisterID: + case certX400Address: { + + current->name.other.data = PORT_ArenaAlloc (arena, strlen (buffer) + 2); + if (current->name.other.data == NULL) { + GEN_BREAK (SECFailure); + } + + PORT_Memcpy (current->name.other.data + 2, buffer, strlen (buffer)); + /* This may not be accurate for all cases. For now, use this tag type */ + current->name.other.data[0] = (char)(((current->type - 1) & 0x1f)| 0x80); + current->name.other.data[1] = (char)strlen (buffer); + current->name.other.len = strlen (buffer) + 2; + break; + } + + case certDirectoryName: { + CERTName *directoryName = NULL; + + directoryName = CERT_AsciiToName (buffer); + if (!directoryName) { + fprintf(stderr, "certutil: improperly formatted name: \"%s\"\n", buffer); + break; + } + + rv = CERT_CopyName (arena, ¤t->name.directoryName, directoryName); + CERT_DestroyName (directoryName); + + break; + } + } + if (rv != SECSuccess) + break; + current->l.next = &(namesList->l); + current->l.prev = &(tail->l); + tail->l.next = &(current->l); + tail = current; + + }while (1); + + if (rv != SECSuccess) { + PORT_SetError (rv); + PORT_ArenaRelease (arena, mark); + namesList = NULL; + } + return (namesList); +} + +static SECStatus +GetString(PRArenaPool *arena, char *prompt, SECItem *value) +{ + char buffer[251]; + + value->data = NULL; + value->len = 0; + + puts (prompt); + gets (buffer); + if (strlen (buffer) > 0) { + value->data = PORT_ArenaAlloc (arena, strlen (buffer)); + if (value->data == NULL) { + PORT_SetError (SEC_ERROR_NO_MEMORY); + return (SECFailure); + } + PORT_Memcpy (value->data, buffer, value->len = strlen(buffer)); + } + return (SECSuccess); +} + +static CERTCertificateRequest * +GetCertRequest(PRFileDesc *inFile, PRBool ascii) +{ + CERTCertificateRequest *certReq = NULL; + CERTSignedData signedData; + PRArenaPool *arena = NULL; + SECItem reqDER; + SECStatus rv; + + reqDER.data = NULL; + do { + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + GEN_BREAK (SECFailure); + } + + rv = SECU_ReadDERFromFile(&reqDER, inFile, ascii); + if (rv) + break; + certReq = (CERTCertificateRequest*) PORT_ArenaZAlloc + (arena, sizeof(CERTCertificateRequest)); + if (!certReq) + break; + certReq->arena = arena; + + /* Since cert request is a signed data, must decode to get the inner + data + */ + PORT_Memset(&signedData, 0, sizeof(signedData)); + rv = SEC_ASN1DecodeItem(arena, &signedData, + SEC_ASN1_GET(CERT_SignedDataTemplate), &reqDER); + if (rv) + break; + + rv = SEC_ASN1DecodeItem(arena, certReq, + SEC_ASN1_GET(CERT_CertificateRequestTemplate), &signedData.data); + } while (0); + + if (!rv) { + rv = CERT_VerifySignedDataWithPublicKeyInfo(&signedData, + &certReq->subjectPublicKeyInfo, NULL /* wincx */); + } + + if (rv) { + PRErrorCode perr = PR_GetError(); + fprintf(stderr, "%s: unable to decode DER cert request (%s)\n", progName, + SECU_Strerror(perr)); + } + return (certReq); +} + +static PRBool +GetYesNo(char *prompt) +{ + char buf[3]; + + PR_Sync(PR_STDIN); + PR_Write(PR_STDOUT, prompt, strlen(prompt)+1); + PR_Read(PR_STDIN, buf, sizeof(buf)); + return (buf[0] == 'y' || buf[0] == 'Y') ? PR_TRUE : PR_FALSE; +#if 0 + char charValue; + + puts (prompt); + scanf ("%c", &charValue); + if (charValue != 'y' && charValue != 'Y') + return (0); + return (1); +#endif +} + +static SECStatus +AddCert(PK11SlotInfo *slot, CERTCertDBHandle *handle, char *name, char *trusts, + PRFileDesc *inFile, PRBool ascii, PRBool emailcert, void *pwdata) +{ + CERTCertTrust *trust = NULL; + CERTCertificate *cert = NULL, *tempCert = NULL; + SECItem certDER; + SECStatus rv; + + certDER.data = NULL; + do { + /* Read in the entire file specified with the -i argument */ + rv = SECU_ReadDERFromFile(&certDER, inFile, ascii); + if (rv != SECSuccess) { + SECU_PrintError(progName, "unable to read input file"); + break; + } + + /* Read in an ASCII cert and return a CERTCertificate */ + cert = CERT_DecodeCertFromPackage((char *)certDER.data, certDER.len); + if (!cert) { + SECU_PrintError(progName, "could not obtain certificate from file"); + GEN_BREAK(SECFailure); + } + + /* Create a cert trust to pass to SEC_AddPermCertificate */ + trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust)); + if (!trust) { + SECU_PrintError(progName, "unable to allocate cert trust"); + GEN_BREAK(SECFailure); + } + + rv = CERT_DecodeTrustString(trust, trusts); + if (rv) { + SECU_PrintError(progName, "unable to decode trust string"); + GEN_BREAK(SECFailure); + } + + if (!PK11_IsFriendly(slot)) { + rv = PK11_Authenticate(slot, PR_TRUE, pwdata); + if (rv != SECSuccess) { + SECU_PrintError(progName, "could not authenticate to token or database"); + GEN_BREAK(SECFailure); + } + } + + rv = PK11_ImportCert(slot, cert, CK_INVALID_HANDLE, name, PR_FALSE); + if (rv != SECSuccess) { + SECU_PrintError(progName, "could not add certificate to token or database"); + GEN_BREAK(SECFailure); + } + + rv = CERT_ChangeCertTrust(handle, cert, trust); + if (rv != SECSuccess) { + SECU_PrintError(progName, "could not change trust on certificate"); + GEN_BREAK(SECFailure); + } + + if ( emailcert ) { + CERT_SaveSMimeProfile(cert, NULL, pwdata); + } + + } while (0); + + CERT_DestroyCertificate (cert); + PORT_Free(trust); + PORT_Free(certDER.data); + + return rv; +} + +/* This function belongs in libNSS somewhere. */ +static SECOidTag +getSignatureOidTag(KeyType keyType, SECOidTag hashAlgTag) +{ + SECOidTag sigTag = SEC_OID_UNKNOWN; + + switch (keyType) { + case rsaKey: + switch (hashAlgTag) { + case SEC_OID_MD2: + sigTag = SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION; break; + case SEC_OID_UNKNOWN: /* default for RSA if not specified */ + case SEC_OID_MD5: + sigTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; break; + case SEC_OID_SHA1: + sigTag = SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; break; + case SEC_OID_SHA256: + sigTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION; break; + case SEC_OID_SHA384: + sigTag = SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION; break; + case SEC_OID_SHA512: + sigTag = SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION; break; + default: + break; + } + break; + case dsaKey: + switch (hashAlgTag) { + case SEC_OID_UNKNOWN: /* default for DSA if not specified */ + case SEC_OID_SHA1: + sigTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; break; + default: + break; + } + break; + default: + break; + } + return sigTag; +} + +static SECStatus +CertReq(SECKEYPrivateKey *privk, SECKEYPublicKey *pubk, KeyType keyType, + SECOidTag hashAlgTag, CERTName *subject, char *phone, int ascii, + const char *emailAddrs, const char *dnsNames, PRFileDesc *outFile) +{ + CERTSubjectPublicKeyInfo *spki; + CERTCertificateRequest *cr; + SECItem *encoding; + SECOidTag signAlgTag; + SECItem result; + SECStatus rv; + PRArenaPool *arena; + PRInt32 numBytes; + + /* Create info about public key */ + spki = SECKEY_CreateSubjectPublicKeyInfo(pubk); + if (!spki) { + SECU_PrintError(progName, "unable to create subject public key"); + return SECFailure; + } + + /* Generate certificate request */ + cr = CERT_CreateCertificateRequest(subject, spki, 0); + if (!cr) { + SECU_PrintError(progName, "unable to make certificate request"); + return SECFailure; + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) { + SECU_PrintError(progName, "out of memory"); + return SECFailure; + } + + /* Der encode the request */ + encoding = SEC_ASN1EncodeItem(arena, NULL, cr, + SEC_ASN1_GET(CERT_CertificateRequestTemplate)); + if (encoding == NULL) { + SECU_PrintError(progName, "der encoding of request failed"); + return SECFailure; + } + + /* Sign the request */ + signAlgTag = getSignatureOidTag(keyType, hashAlgTag); + if (signAlgTag == SEC_OID_UNKNOWN) { + SECU_PrintError(progName, "unknown Key or Hash type"); + return SECFailure; + } + rv = SEC_DerSignData(arena, &result, encoding->data, encoding->len, + privk, signAlgTag); + if (rv) { + SECU_PrintError(progName, "signing of data failed"); + return SECFailure; + } + + /* Encode request in specified format */ + if (ascii) { + char *obuf; + char *name, *email, *org, *state, *country; + SECItem *it; + int total; + + it = &result; + + obuf = BTOA_ConvertItemToAscii(it); + total = PL_strlen(obuf); + + name = CERT_GetCommonName(subject); + if (!name) { + fprintf(stderr, "You must specify a common name\n"); + return SECFailure; + } + + if (!phone) + phone = strdup("(not specified)"); + + email = CERT_GetCertEmailAddress(subject); + if (!email) + email = strdup("(not specified)"); + + org = CERT_GetOrgName(subject); + if (!org) + org = strdup("(not specified)"); + + state = CERT_GetStateName(subject); + if (!state) + state = strdup("(not specified)"); + + country = CERT_GetCountryName(subject); + if (!country) + country = strdup("(not specified)"); + + PR_fprintf(outFile, + "\nCertificate request generated by Netscape certutil\n"); + PR_fprintf(outFile, "Phone: %s\n\n", phone); + PR_fprintf(outFile, "Common Name: %s\n", name); + PR_fprintf(outFile, "Email: %s\n", email); + PR_fprintf(outFile, "Organization: %s\n", org); + PR_fprintf(outFile, "State: %s\n", state); + PR_fprintf(outFile, "Country: %s\n\n", country); + + PR_fprintf(outFile, "%s\n", NS_CERTREQ_HEADER); + numBytes = PR_Write(outFile, obuf, total); + if (numBytes != total) { + SECU_PrintSystemError(progName, "write error"); + return SECFailure; + } + PR_fprintf(outFile, "\n%s\n", NS_CERTREQ_TRAILER); + } else { + numBytes = PR_Write(outFile, result.data, result.len); + if (numBytes != (int)result.len) { + SECU_PrintSystemError(progName, "write error"); + return SECFailure; + } + } + return SECSuccess; +} + +static SECStatus +ChangeTrustAttributes(CERTCertDBHandle *handle, char *name, char *trusts) +{ + SECStatus rv; + CERTCertificate *cert; + CERTCertTrust *trust; + + cert = CERT_FindCertByNicknameOrEmailAddr(handle, name); + if (!cert) { + SECU_PrintError(progName, "could not find certificate named \"%s\"", + name); + return SECFailure; + } + + trust = (CERTCertTrust *)PORT_ZAlloc(sizeof(CERTCertTrust)); + if (!trust) { + SECU_PrintError(progName, "unable to allocate cert trust"); + return SECFailure; + } + + /* This function only decodes these characters: pPwcTCu, */ + rv = CERT_DecodeTrustString(trust, trusts); + if (rv) { + SECU_PrintError(progName, "unable to decode trust string"); + return SECFailure; + } + + rv = CERT_ChangeCertTrust(handle, cert, trust); + if (rv) { + SECU_PrintError(progName, "unable to modify trust attributes"); + return SECFailure; + } + CERT_DestroyCertificate(cert); + + return SECSuccess; +} + +static SECStatus +printCertCB(CERTCertificate *cert, void *arg) +{ + SECStatus rv; + SECItem data; + CERTCertTrust *trust = (CERTCertTrust *)arg; + + data.data = cert->derCert.data; + data.len = cert->derCert.len; + + rv = SECU_PrintSignedData(stdout, &data, "Certificate", 0, + SECU_PrintCertificate); + if (rv) { + SECU_PrintError(progName, "problem printing certificate"); + return(SECFailure); + } + if (trust) { + SECU_PrintTrustFlags(stdout, trust, + "Certificate Trust Flags", 1); + } else if (cert->trust) { + SECU_PrintTrustFlags(stdout, cert->trust, + "Certificate Trust Flags", 1); + } + + printf("\n"); + + return(SECSuccess); +} + +static SECStatus +DumpChain(CERTCertDBHandle *handle, char *name) +{ + CERTCertificate *the_cert; + CERTCertificateList *chain; + int i, j; + the_cert = PK11_FindCertFromNickname(name, NULL); + if (!the_cert) { + SECU_PrintError(progName, "Could not find: %s\n", name); + return SECFailure; + } + chain = CERT_CertChainFromCert(the_cert, 0, PR_TRUE); + CERT_DestroyCertificate(the_cert); + if (!chain) { + SECU_PrintError(progName, "Could not obtain chain for: %s\n", name); + return SECFailure; + } + for (i=chain->len-1; i>=0; i--) { + CERTCertificate *c; + c = CERT_FindCertByDERCert(handle, &chain->certs[i]); + for (j=i; j<chain->len-1; j++) printf(" "); + printf("\"%s\" [%s]\n\n", c->nickname, c->subjectName); + CERT_DestroyCertificate(c); + } + CERT_DestroyCertificateList(chain); + return SECSuccess; +} + +static SECStatus +listCerts(CERTCertDBHandle *handle, char *name, PK11SlotInfo *slot, + PRBool raw, PRBool ascii, PRFileDesc *outfile, void *pwarg) +{ + SECItem data; + PRInt32 numBytes; + SECStatus rv = SECFailure; + CERTCertList *certs; + CERTCertListNode *node; + + /* List certs on a non-internal slot. */ + if (!PK11_IsFriendly(slot) && PK11_NeedLogin(slot)) + PK11_Authenticate(slot, PR_TRUE, pwarg); + if (name) { + CERTCertificate *the_cert; + the_cert = CERT_FindCertByNicknameOrEmailAddr(handle, name); + if (!the_cert) { + the_cert = PK11_FindCertFromNickname(name, NULL); + if (!the_cert) { + SECU_PrintError(progName, "Could not find: %s\n", name); + return SECFailure; + } + } + certs = CERT_CreateSubjectCertList(NULL, handle, &the_cert->derSubject, + PR_Now(), PR_FALSE); + CERT_DestroyCertificate(the_cert); + + for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node,certs); + node = CERT_LIST_NEXT(node)) { + the_cert = node->cert; + /* now get the subjectList that matches this cert */ + data.data = the_cert->derCert.data; + data.len = the_cert->derCert.len; + if (ascii) { + PR_fprintf(outfile, "%s\n%s\n%s\n", NS_CERT_HEADER, + BTOA_DataToAscii(data.data, data.len), NS_CERT_TRAILER); + rv = SECSuccess; + } else if (raw) { + numBytes = PR_Write(outfile, data.data, data.len); + if (numBytes != data.len) { + SECU_PrintSystemError(progName, "error writing raw cert"); + rv = SECFailure; + } + rv = SECSuccess; + } else { + rv = printCertCB(the_cert, the_cert->trust); + } + if (rv != SECSuccess) { + break; + } + } + } else { + + certs = PK11_ListCertsInSlot(slot); + if (certs) { + for (node = CERT_LIST_HEAD(certs); !CERT_LIST_END(node,certs); + node = CERT_LIST_NEXT(node)) { + SECU_PrintCertNickname(node->cert,stdout); + } + rv = SECSuccess; + } + } + CERT_DestroyCertList(certs); + if (rv) { + SECU_PrintError(progName, "problem printing certificate nicknames"); + return SECFailure; + } + + return SECSuccess; /* not rv ?? */ +} + +static SECStatus +ListCerts(CERTCertDBHandle *handle, char *name, PK11SlotInfo *slot, + PRBool raw, PRBool ascii, PRFileDesc *outfile, secuPWData *pwdata) +{ + SECStatus rv; + + if (slot == NULL) { + CERTCertList *list; + CERTCertListNode *node; + + list = PK11_ListCerts(PK11CertListUnique, pwdata); + for (node = CERT_LIST_HEAD(list); !CERT_LIST_END(node, list); + node = CERT_LIST_NEXT(node)) + { + SECU_PrintCertNickname(node->cert, stdout); + } + CERT_DestroyCertList(list); + return SECSuccess; + } else { + rv = listCerts(handle,name,slot,raw,ascii,outfile,pwdata); + } + return rv; +} + +static SECStatus +DeleteCert(CERTCertDBHandle *handle, char *name) +{ + SECStatus rv; + CERTCertificate *cert; + + cert = CERT_FindCertByNicknameOrEmailAddr(handle, name); + if (!cert) { + SECU_PrintError(progName, "could not find certificate named \"%s\"", + name); + return SECFailure; + } + + rv = SEC_DeletePermCertificate(cert); + CERT_DestroyCertificate(cert); + if (rv) { + SECU_PrintError(progName, "unable to delete certificate"); + return SECFailure; + } + + return SECSuccess; +} + +static SECStatus +ValidateCert(CERTCertDBHandle *handle, char *name, char *date, + char *certUsage, PRBool checkSig, PRBool logit, secuPWData *pwdata) +{ + SECStatus rv; + CERTCertificate *cert = NULL; + int64 timeBoundary; + SECCertificateUsage usage; + CERTVerifyLog reallog; + CERTVerifyLog *log = NULL; + + switch (*certUsage) { + case 'C': + usage = certificateUsageSSLClient; + break; + case 'V': + usage = certificateUsageSSLServer; + break; + case 'S': + usage = certificateUsageEmailSigner; + break; + case 'R': + usage = certificateUsageEmailRecipient; + break; + default: + PORT_SetError (SEC_ERROR_INVALID_ARGS); + return (SECFailure); + } + do { + cert = CERT_FindCertByNicknameOrEmailAddr(handle, name); + if (!cert) { + SECU_PrintError(progName, "could not find certificate named \"%s\"", + name); + GEN_BREAK (SECFailure) + } + + if (date != NULL) { + rv = DER_AsciiToTime(&timeBoundary, date); + if (rv) { + SECU_PrintError(progName, "invalid input date"); + GEN_BREAK (SECFailure) + } + } else { + timeBoundary = PR_Now(); + } + + if ( logit ) { + log = &reallog; + + log->count = 0; + log->head = NULL; + log->tail = NULL; + log->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( log->arena == NULL ) { + SECU_PrintError(progName, "out of memory"); + GEN_BREAK (SECFailure) + } + } + + rv = CERT_VerifyCertificate(handle, cert, checkSig, usage, + timeBoundary, pwdata, log, &usage); + if ( log ) { + if ( log->head == NULL ) { + fprintf(stdout, "%s: certificate is valid\n", progName); + GEN_BREAK (SECSuccess) + } else { + char *name; + CERTVerifyLogNode *node; + + node = log->head; + while ( node ) { + if ( node->cert->nickname != NULL ) { + name = node->cert->nickname; + } else { + name = node->cert->subjectName; + } + fprintf(stderr, "%s : %s\n", name, + SECU_Strerror(node->error)); + CERT_DestroyCertificate(node->cert); + node = node->next; + } + } + } else { + if (rv != SECSuccess) { + PRErrorCode perr = PORT_GetError(); + fprintf(stdout, "%s: certificate is invalid: %s\n", + progName, SECU_Strerror(perr)); + GEN_BREAK (SECFailure) + } + fprintf(stdout, "%s: certificate is valid\n", progName); + GEN_BREAK (SECSuccess) + } + } while (0); + + if (cert) { + CERT_DestroyCertificate(cert); + } + + return (rv); +} + + +static SECStatus +printKeyCB(SECKEYPublicKey *key, SECItem *data, void *arg) +{ + if (key->keyType == rsaKey) { + fprintf(stdout, "RSA Public-Key:\n"); + SECU_PrintInteger(stdout, &key->u.rsa.modulus, "modulus", 1); + } else { + fprintf(stdout, "DSA Public-Key:\n"); + SECU_PrintInteger(stdout, &key->u.dsa.publicValue, "publicValue", 1); + } + return SECSuccess; +} + +/* callback for listing certs through pkcs11 */ +static SECStatus +secu_PrintKey(FILE *out, int count, SECKEYPrivateKey *key) +{ + char *name; + + name = PK11_GetPrivateKeyNickname(key); + if (name == NULL) { + /* should look up associated cert */ + name = PORT_Strdup("< orphaned >"); + } + fprintf(out, "<%d> %s\n", count, name); + PORT_Free(name); + + return SECSuccess; +} + +static SECStatus +listKeys(PK11SlotInfo *slot, KeyType keyType, void *pwarg) +{ + SECKEYPrivateKeyList *list; + SECKEYPrivateKeyListNode *node; + int count; + + if (PK11_NeedLogin(slot)) + PK11_Authenticate(slot, PR_TRUE, pwarg); + + list = PK11_ListPrivateKeysInSlot(slot); + if (list == NULL) { + SECU_PrintError(progName, "problem listing keys"); + return SECFailure; + } + for (count=0, node=PRIVKEY_LIST_HEAD(list) ; !PRIVKEY_LIST_END(node,list); + node= PRIVKEY_LIST_NEXT(node),count++) { + secu_PrintKey(stdout, count, node->key); + } + SECKEY_DestroyPrivateKeyList(list); + + if (count == 0) { + fprintf(stderr, "%s: no keys found\n", progName); + return SECFailure; + } + return SECSuccess; +} + +static SECStatus +ListKeys(PK11SlotInfo *slot, char *keyname, int index, + KeyType keyType, PRBool dopriv, secuPWData *pwdata) +{ + SECStatus rv = SECSuccess; + + if (slot == NULL) { + PK11SlotList *list; + PK11SlotListElement *le; + + list= PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,pwdata); + if (list) for (le = list->head; le; le = le->next) { + rv = listKeys(le->slot,keyType,pwdata); + } + } else { + rv = listKeys(slot,keyType,pwdata); + } + return rv; +} + +static SECStatus +DeleteKey(char *nickname, secuPWData *pwdata) +{ + SECStatus rv; + CERTCertificate *cert; + PK11SlotInfo *slot; + + slot = PK11_GetInternalKeySlot(); + if (PK11_NeedLogin(slot)) + PK11_Authenticate(slot, PR_TRUE, pwdata); + cert = PK11_FindCertFromNickname(nickname, pwdata); + if (!cert) { + PK11_FreeSlot(slot); + return SECFailure; + } + rv = PK11_DeleteTokenCertAndKey(cert, pwdata); + if (rv != SECSuccess) { + SECU_PrintError("problem deleting private key \"%s\"\n", nickname); + } + CERT_DestroyCertificate(cert); + PK11_FreeSlot(slot); + return rv; +} + + +/* + * L i s t M o d u l e s + * + * Print a list of the PKCS11 modules that are + * available. This is useful for smartcard people to + * make sure they have the drivers loaded. + * + */ +static SECStatus +ListModules(void) +{ + PK11SlotList *list; + PK11SlotListElement *le; + + /* get them all! */ + list = PK11_GetAllTokens(CKM_INVALID_MECHANISM,PR_FALSE,PR_FALSE,NULL); + if (list == NULL) return SECFailure; + + /* look at each slot*/ + for (le = list->head ; le; le = le->next) { + printf ("\n"); + printf (" slot: %s\n", PK11_GetSlotName(le->slot)); + printf (" token: %s\n", PK11_GetTokenName(le->slot)); + } + PK11_FreeSlotList(list); + + return SECSuccess; +} + +static void +Usage(char *progName) +{ +#define FPS fprintf(stderr, + FPS "Type %s -H for more detailed descriptions\n", progName); + FPS "Usage: %s -N [-d certdir] [-P dbprefix] [-f pwfile]\n", progName); + FPS "Usage: %s -T [-d certdir] [-P dbprefix] [-h token-name] [-f pwfile]\n", progName); + FPS "\t%s -A -n cert-name -t trustargs [-d certdir] [-P dbprefix] [-a] [-i input]\n", + progName); + FPS "\t%s -C [-c issuer-name | -x] -i cert-request-file -o cert-file\n" + "\t\t [-m serial-number] [-w warp-months] [-v months-valid]\n" + "\t\t [-f pwfile] [-d certdir] [-P dbprefix] [-1] [-2] [-3] [-4] [-5]\n" + "\t\t [-6] [-7 emailAddrs] [-8 dns-names]\n", + progName); + FPS "\t%s -D -n cert-name [-d certdir] [-P dbprefix]\n", progName); + FPS "\t%s -E -n cert-name -t trustargs [-d certdir] [-P dbprefix] [-a] [-i input]\n", + progName); + FPS "\t%s -G -n key-name [-h token-name] [-k rsa] [-g key-size] [-y exp]\n" + "\t\t [-f pwfile] [-z noisefile] [-d certdir] [-P dbprefix]\n", progName); + FPS "\t%s -G [-h token-name] -k dsa [-q pqgfile -g key-size] [-f pwfile]\n" + "\t\t [-z noisefile] [-d certdir] [-P dbprefix]\n", progName); + FPS "\t%s -K [-n key-name] [-h token-name] [-k dsa|rsa|all]\n", + progName); + FPS "\t\t [-f pwfile] [-X] [-d certdir] [-P dbprefix]\n"); + FPS "\t%s -L [-n cert-name] [-X] [-d certdir] [-P dbprefix] [-r] [-a]\n", progName); + FPS "\t%s -M -n cert-name -t trustargs [-d certdir] [-P dbprefix]\n", + progName); + FPS "\t%s -O -n cert-name [-X] [-d certdir] [-P dbprefix]\n", progName); + FPS "\t%s -R -s subj -o cert-request-file [-d certdir] [-P dbprefix] [-p phone] [-a]\n" + "\t\t [-y emailAddrs] [-k key-type] [-h token-name] [-f pwfile] [-g key-size]\n", + progName); + FPS "\t%s -V -n cert-name -u usage [-b time] [-e] \n" + "\t\t[-X] [-d certdir] [-P dbprefix]\n", + progName); + FPS "\t%s -S -n cert-name -s subj [-c issuer-name | -x] -t trustargs\n" + "\t\t [-k key-type] [-h token-name] [-g key-size]\n" + "\t\t [-m serial-number] [-w warp-months] [-v months-valid]\n" + "\t\t [-f pwfile] [-d certdir] [-P dbprefix]\n" + "\t\t [-p phone] [-1] [-2] [-3] [-4] [-5] [-6] [-7 emailAddrs]\n" + "\t\t [-8 dns-names]\n", + progName); + FPS "\t%s -U [-X] [-d certdir] [-P dbprefix]\n", progName); + exit(1); +} + +static void LongUsage(char *progName) +{ + + FPS "%-15s Add a certificate to the database (create if needed)\n", + "-A"); + FPS "%-15s Add an Email certificate to the database (create if needed)\n", + "-E"); + FPS "%-20s Specify the nickname of the certificate to add\n", + " -n cert-name"); + FPS "%-20s Set the certificate trust attributes:\n", + " -t trustargs"); + FPS "%-25s p \t valid peer\n", ""); + FPS "%-25s P \t trusted peer (implies p)\n", ""); + FPS "%-25s c \t valid CA\n", ""); + FPS "%-25s T \t trusted CA to issue client certs (implies c)\n", ""); + FPS "%-25s C \t trusted CA to issue server certs (implies c)\n", ""); + FPS "%-25s u \t user cert\n", ""); + FPS "%-25s w \t send warning\n", ""); +#ifdef DEBUG_NSSTEAM_ONLY + FPS "%-25s g \t make step-up cert\n", ""); +#endif /* DEBUG_NSSTEAM_ONLY */ + FPS "%-20s Specify the password file\n", + " -f pwfile"); + FPS "%-20s Cert database directory (default is ~/.netscape)\n", + " -d certdir"); + FPS "%-20s Cert & Key database prefix\n", + " -P dbprefix"); + FPS "%-20s The input certificate is encoded in ASCII (RFC1113)\n", + " -a"); + FPS "%-20s Specify the certificate file (default is stdin)\n", + " -i input"); + FPS "\n"); + + FPS "%-15s Create a new binary certificate from a BINARY cert request\n", + "-C"); + FPS "%-20s The nickname of the issuer cert\n", + " -c issuer-name"); + FPS "%-20s The BINARY certificate request file\n", + " -i cert-request "); + FPS "%-20s Output binary cert to this file (default is stdout)\n", + " -o output-cert"); + FPS "%-20s Self sign\n", + " -x"); + FPS "%-20s Cert serial number\n", + " -m serial-number"); + FPS "%-20s Time Warp\n", + " -w warp-months"); + FPS "%-20s Months valid (default is 3)\n", + " -v months-valid"); + FPS "%-20s Specify the password file\n", + " -f pwfile"); + FPS "%-20s Cert database directory (default is ~/.netscape)\n", + " -d certdir"); + FPS "%-20s Cert & Key database prefix\n", + " -P dbprefix"); + FPS "%-20s Create key usage extension\n", + " -1 "); + FPS "%-20s Create basic constraint extension\n", + " -2 "); + FPS "%-20s Create authority key ID extension\n", + " -3 "); + FPS "%-20s Create crl distribution point extension\n", + " -4 "); + FPS "%-20s Create netscape cert type extension\n", + " -5 "); + FPS "%-20s Create extended key usage extension\n", + " -6 "); + FPS "%-20s Create an email subject alt name extension\n", + " -7 "); + FPS "%-20s Create an dns subject alt name extension\n", + " -8 "); + FPS "\n"); + + FPS "%-15s Generate a new key pair\n", + "-G"); + FPS "%-20s Name of token in which to generate key (default is internal)\n", + " -h token-name"); + FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n", + " -k key-type"); + FPS "%-20s Key size in bits, (min %d, max %d, default %d)\n", + " -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS); + FPS "%-20s Set the public exponent value (3, 17, 65537) (rsa only)\n", + " -y exp"); + FPS "%-20s Specify the password file\n", + " -f password-file"); + FPS "%-20s Specify the noise file to be used\n", + " -z noisefile"); + FPS "%-20s read PQG value from pqgfile (dsa only)\n", + " -q pqgfile"); + FPS "%-20s Key database directory (default is ~/.netscape)\n", + " -d keydir"); + FPS "%-20s Cert & Key database prefix\n", + " -P dbprefix"); + FPS "\n"); + + FPS "%-15s Delete a certificate from the database\n", + "-D"); + FPS "%-20s The nickname of the cert to delete\n", + " -n cert-name"); + FPS "%-20s Cert database directory (default is ~/.netscape)\n", + " -d certdir"); + FPS "%-20s Cert & Key database prefix\n", + " -P dbprefix"); + FPS "\n"); + + FPS "%-15s List all modules\n", /*, or print out a single named module\n",*/ + "-U"); + FPS "%-20s Module database directory (default is '~/.netscape')\n", + " -d moddir"); + FPS "%-20s Cert & Key database prefix\n", + " -P dbprefix"); + FPS "%-20s force the database to open R/W\n", + " -X"); + FPS "\n"); + + FPS "%-15s List all keys\n", /*, or print out a single named key\n",*/ + "-K"); + FPS "%-20s Name of token in which to look for keys (default is internal," + " use \"all\" to list keys on all tokens)\n", + " -h token-name "); + FPS "%-20s Type of key pair to list (\"all\", \"dsa\", \"rsa\" (default))\n", + " -k key-type"); + FPS "%-20s Specify the password file\n", + " -f password-file"); + FPS "%-20s Key database directory (default is ~/.netscape)\n", + " -d keydir"); + FPS "%-20s Cert & Key database prefix\n", + " -P dbprefix"); + FPS "%-20s force the database to open R/W\n", + " -X"); + FPS "\n"); + + FPS "%-15s List all certs, or print out a single named cert\n", + "-L"); + FPS "%-20s Pretty print named cert (list all if unspecified)\n", + " -n cert-name"); + FPS "%-20s Cert database directory (default is ~/.netscape)\n", + " -d certdir"); + FPS "%-20s Cert & Key database prefix\n", + " -P dbprefix"); + FPS "%-20s force the database to open R/W\n", + " -X"); + FPS "%-20s For single cert, print binary DER encoding\n", + " -r"); + FPS "%-20s For single cert, print ASCII encoding (RFC1113)\n", + " -a"); + FPS "\n"); + + FPS "%-15s Modify trust attributes of certificate\n", + "-M"); + FPS "%-20s The nickname of the cert to modify\n", + " -n cert-name"); + FPS "%-20s Set the certificate trust attributes (see -A above)\n", + " -t trustargs"); + FPS "%-20s Cert database directory (default is ~/.netscape)\n", + " -d certdir"); + FPS "%-20s Cert & Key database prefix\n", + " -P dbprefix"); + FPS "\n"); + + FPS "%-15s Create a new certificate database\n", + "-N"); + FPS "%-20s Cert database directory (default is ~/.netscape)\n", + " -d certdir"); + FPS "%-20s Cert & Key database prefix\n", + " -P dbprefix"); + FPS "\n"); + FPS "%-15s Reset the Key database or token\n", + "-T"); + FPS "%-20s Cert database directory (default is ~/.netscape)\n", + " -d certdir"); + FPS "%-20s Cert & Key database prefix\n", + " -P dbprefix"); + FPS "%-20s Token to reset (default is internal)\n", + " -h token-name"); + FPS "\n"); + + FPS "\n"); + FPS "%-15s Print the chain of a certificate\n", + "-O"); + FPS "%-20s The nickname of the cert to modify\n", + " -n cert-name"); + FPS "%-20s Cert database directory (default is ~/.netscape)\n", + " -d certdir"); + FPS "%-20s Cert & Key database prefix\n", + " -P dbprefix"); + FPS "%-20s force the database to open R/W\n", + " -X"); + FPS "\n"); + + FPS "%-15s Generate a certificate request (stdout)\n", + "-R"); + FPS "%-20s Specify the subject name (using RFC1485)\n", + " -s subject"); + FPS "%-20s Output the cert request to this file\n", + " -o output-req"); + FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n", + " -k key-type"); + FPS "%-20s Name of token in which to generate key (default is internal)\n", + " -h token-name"); + FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n", + " -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS); + FPS "%-20s Specify the password file\n", + " -f pwfile"); + FPS "%-20s Key database directory (default is ~/.netscape)\n", + " -d keydir"); + FPS "%-20s Cert & Key database prefix\n", + " -P dbprefix"); + FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n", + " -p phone"); + FPS "%-20s Output the cert request in ASCII (RFC1113); default is binary\n", + " -a"); + FPS "\n"); + + FPS "%-15s Validate a certificate\n", + "-V"); + FPS "%-20s The nickname of the cert to Validate\n", + " -n cert-name"); + FPS "%-20s validity time (\"YYMMDDHHMMSS[+HHMM|-HHMM|Z]\")\n", + " -b time"); + FPS "%-20s Check certificate signature \n", + " -e "); + FPS "%-20s Specify certificate usage:\n", " -u certusage"); + FPS "%-25s C \t SSL Client\n", ""); + FPS "%-25s V \t SSL Server\n", ""); + FPS "%-25s S \t Email signer\n", ""); + FPS "%-25s R \t Email Recipient\n", ""); + FPS "%-20s Cert database directory (default is ~/.netscape)\n", + " -d certdir"); + FPS "%-20s Cert & Key database prefix\n", + " -P dbprefix"); + FPS "%-20s force the database to open R/W\n", + " -X"); + FPS "\n"); + + FPS "%-15s Make a certificate and add to database\n", + "-S"); + FPS "%-20s Specify the nickname of the cert\n", + " -n key-name"); + FPS "%-20s Specify the subject name (using RFC1485)\n", + " -s subject"); + FPS "%-20s The nickname of the issuer cert\n", + " -c issuer-name"); + FPS "%-20s Set the certificate trust attributes (see -A above)\n", + " -t trustargs"); + FPS "%-20s Type of key pair to generate (\"dsa\", \"rsa\" (default))\n", + " -k key-type"); + FPS "%-20s Name of token in which to generate key (default is internal)\n", + " -h token-name"); + FPS "%-20s Key size in bits, RSA keys only (min %d, max %d, default %d)\n", + " -g key-size", MIN_KEY_BITS, MAX_KEY_BITS, DEFAULT_KEY_BITS); + FPS "%-20s Self sign\n", + " -x"); + FPS "%-20s Cert serial number\n", + " -m serial-number"); + FPS "%-20s Time Warp\n", + " -w warp-months"); + FPS "%-20s Months valid (default is 3)\n", + " -v months-valid"); + FPS "%-20s Specify the password file\n", + " -f pwfile"); + FPS "%-20s Cert database directory (default is ~/.netscape)\n", + " -d certdir"); + FPS "%-20s Cert & Key database prefix\n", + " -P dbprefix"); + FPS "%-20s Specify the contact phone number (\"123-456-7890\")\n", + " -p phone"); + FPS "%-20s Create key usage extension\n", + " -1 "); + FPS "%-20s Create basic constraint extension\n", + " -2 "); + FPS "%-20s Create authority key ID extension\n", + " -3 "); + FPS "%-20s Create crl distribution point extension\n", + " -4 "); + FPS "%-20s Create netscape cert type extension\n", + " -5 "); + FPS "%-20s Create extended key usage extension\n", + " -6 "); + FPS "%-20s Create an email subject alt name extension\n", + " -7 "); + FPS "%-20s Create an dns subject alt name extension\n", + " -8 "); + FPS "\n"); + + exit(1); +#undef FPS +} + + +static CERTCertificate * +MakeV1Cert( CERTCertDBHandle * handle, + CERTCertificateRequest *req, + char * issuerNickName, + PRBool selfsign, + unsigned int serialNumber, + int warpmonths, + int validitylength) +{ + CERTCertificate *issuerCert = NULL; + CERTValidity *validity; + CERTCertificate *cert = NULL; + PRExplodedTime printableTime; + PRTime now, after; + + if ( !selfsign ) { + issuerCert = CERT_FindCertByNicknameOrEmailAddr(handle, issuerNickName); + if (!issuerCert) { + SECU_PrintError(progName, "could not find certificate named \"%s\"", + issuerNickName); + return NULL; + } + } + + now = PR_Now(); + PR_ExplodeTime (now, PR_GMTParameters, &printableTime); + if ( warpmonths ) { + printableTime.tm_month += warpmonths; + now = PR_ImplodeTime (&printableTime); + PR_ExplodeTime (now, PR_GMTParameters, &printableTime); + } + printableTime.tm_month += validitylength; + printableTime.tm_month += 3; + after = PR_ImplodeTime (&printableTime); + + /* note that the time is now in micro-second unit */ + validity = CERT_CreateValidity (now, after); + + cert = CERT_CreateCertificate(serialNumber, + (selfsign ? &req->subject + : &issuerCert->subject), + validity, req); + + CERT_DestroyValidity(validity); + if ( issuerCert ) { + CERT_DestroyCertificate (issuerCert); + } + + return(cert); +} + +static SECStatus +AddKeyUsage (void *extHandle) +{ + SECItem bitStringValue; + unsigned char keyUsage = 0x0; + char buffer[5]; + int value; + + while (1) { + fprintf(stdout, "%-25s 0 - Digital Signature\n", ""); + fprintf(stdout, "%-25s 1 - Non-repudiation\n", ""); + fprintf(stdout, "%-25s 2 - Key encipherment\n", ""); + fprintf(stdout, "%-25s 3 - Data encipherment\n", ""); + fprintf(stdout, "%-25s 4 - Key agreement\n", ""); + fprintf(stdout, "%-25s 5 - Cert signing key\n", ""); + fprintf(stdout, "%-25s 6 - CRL signing key\n", ""); + fprintf(stdout, "%-25s Other to finish\n", ""); + if (gets (buffer)) { + value = atoi (buffer); + if (value < 0 || value > 6) + break; + keyUsage |= (0x80 >> value); + } + else { /* gets() returns NULL on EOF or error */ + break; + } + } + + bitStringValue.data = &keyUsage; + bitStringValue.len = 1; + buffer[0] = 'n'; + puts ("Is this a critical extension [y/n]? "); + gets (buffer); + + return (CERT_EncodeAndAddBitStrExtension + (extHandle, SEC_OID_X509_KEY_USAGE, &bitStringValue, + (buffer[0] == 'y' || buffer[0] == 'Y') ? PR_TRUE : PR_FALSE)); + +} + + +static CERTOidSequence * +CreateOidSequence(void) +{ + CERTOidSequence *rv = (CERTOidSequence *)NULL; + PRArenaPool *arena = (PRArenaPool *)NULL; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if( (PRArenaPool *)NULL == arena ) { + goto loser; + } + + rv = (CERTOidSequence *)PORT_ArenaZAlloc(arena, sizeof(CERTOidSequence)); + if( (CERTOidSequence *)NULL == rv ) { + goto loser; + } + + rv->oids = (SECItem **)PORT_ArenaZAlloc(arena, sizeof(SECItem *)); + if( (SECItem **)NULL == rv->oids ) { + goto loser; + } + + rv->arena = arena; + return rv; + + loser: + if( (PRArenaPool *)NULL != arena ) { + PORT_FreeArena(arena, PR_FALSE); + } + + return (CERTOidSequence *)NULL; +} + +static void +DestroyOidSequence(CERTOidSequence *os) +{ + if (os->arena) { + PORT_FreeArena(os->arena, PR_FALSE); + } +} + +static SECStatus +AddOidToSequence(CERTOidSequence *os, SECOidTag oidTag) +{ + SECItem **oids; + PRUint32 count = 0; + SECOidData *od; + + od = SECOID_FindOIDByTag(oidTag); + if( (SECOidData *)NULL == od ) { + return SECFailure; + } + + for( oids = os->oids; (SECItem *)NULL != *oids; oids++ ) { + count++; + } + + /* ArenaZRealloc */ + + { + PRUint32 i; + + oids = (SECItem **)PORT_ArenaZAlloc(os->arena, sizeof(SECItem *) * (count+2)); + if( (SECItem **)NULL == oids ) { + return SECFailure; + } + + for( i = 0; i < count; i++ ) { + oids[i] = os->oids[i]; + } + + /* ArenaZFree(os->oids); */ + } + + os->oids = oids; + os->oids[count] = &od->oid; + + return SECSuccess; +} + +SEC_ASN1_MKSUB(SEC_ObjectIDTemplate); + +const SEC_ASN1Template CERT_OidSeqTemplate[] = { + { SEC_ASN1_SEQUENCE_OF | SEC_ASN1_XTRN, + offsetof(CERTOidSequence, oids), + SEC_ASN1_SUB(SEC_ObjectIDTemplate) } +}; + + +static SECItem * +EncodeOidSequence(CERTOidSequence *os) +{ + SECItem *rv; + + rv = (SECItem *)PORT_ArenaZAlloc(os->arena, sizeof(SECItem)); + if( (SECItem *)NULL == rv ) { + goto loser; + } + + if( !SEC_ASN1EncodeItem(os->arena, rv, os, CERT_OidSeqTemplate) ) { + goto loser; + } + + return rv; + + loser: + return (SECItem *)NULL; +} + +static SECStatus +AddExtKeyUsage (void *extHandle) +{ + char buffer[5]; + int value; + CERTOidSequence *os; + SECStatus rv; + SECItem *item; + + os = CreateOidSequence(); + if( (CERTOidSequence *)NULL == os ) { + return SECFailure; + } + + while (1) { + fprintf(stdout, "%-25s 0 - Server Auth\n", ""); + fprintf(stdout, "%-25s 1 - Client Auth\n", ""); + fprintf(stdout, "%-25s 2 - Code Signing\n", ""); + fprintf(stdout, "%-25s 3 - Email Protection\n", ""); + fprintf(stdout, "%-25s 4 - Timestamp\n", ""); + fprintf(stdout, "%-25s 5 - OCSP Responder\n", ""); +#ifdef DEBUG_NSSTEAM_ONLY + fprintf(stdout, "%-25s 6 - Step-up\n", ""); +#endif /* DEBUG_NSSTEAM_ONLY */ + fprintf(stdout, "%-25s Other to finish\n", ""); + + gets(buffer); + value = atoi(buffer); + + switch( value ) { + case 0: + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH); + break; + case 1: + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH); + break; + case 2: + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_CODE_SIGN); + break; + case 3: + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT); + break; + case 4: + rv = AddOidToSequence(os, SEC_OID_EXT_KEY_USAGE_TIME_STAMP); + break; + case 5: + rv = AddOidToSequence(os, SEC_OID_OCSP_RESPONDER); + break; +#ifdef DEBUG_NSSTEAM_ONLY + case 6: + rv = AddOidToSequence(os, SEC_OID_NS_KEY_USAGE_GOVT_APPROVED); + break; +#endif /* DEBUG_NSSTEAM_ONLY */ + default: + goto endloop; + } + + if( SECSuccess != rv ) goto loser; + } + + endloop:; + item = EncodeOidSequence(os); + + buffer[0] = 'n'; + puts ("Is this a critical extension [y/n]? "); + gets (buffer); + + rv = CERT_AddExtension(extHandle, SEC_OID_X509_EXT_KEY_USAGE, item, + ((buffer[0] == 'y' || buffer[0] == 'Y') + ? PR_TRUE : PR_FALSE), PR_TRUE); + /*FALLTHROUGH*/ + loser: + DestroyOidSequence(os); + return rv; +} + +static SECStatus +AddNscpCertType (void *extHandle) +{ + SECItem bitStringValue; + unsigned char keyUsage = 0x0; + char buffer[5]; + int value; + + while (1) { + fprintf(stdout, "%-25s 0 - SSL Client\n", ""); + fprintf(stdout, "%-25s 1 - SSL Server\n", ""); + fprintf(stdout, "%-25s 2 - S/MIME\n", ""); + fprintf(stdout, "%-25s 3 - Object Signing\n", ""); + fprintf(stdout, "%-25s 4 - Reserved for futuer use\n", ""); + fprintf(stdout, "%-25s 5 - SSL CA\n", ""); + fprintf(stdout, "%-25s 6 - S/MIME CA\n", ""); + fprintf(stdout, "%-25s 7 - Object Signing CA\n", ""); + fprintf(stdout, "%-25s Other to finish\n", ""); + gets (buffer); + value = atoi (buffer); + if (value < 0 || value > 7) + break; + keyUsage |= (0x80 >> value); + } + + bitStringValue.data = &keyUsage; + bitStringValue.len = 1; + buffer[0] = 'n'; + puts ("Is this a critical extension [y/n]? "); + gets (buffer); + + return (CERT_EncodeAndAddBitStrExtension + (extHandle, SEC_OID_NS_CERT_EXT_CERT_TYPE, &bitStringValue, + (buffer[0] == 'y' || buffer[0] == 'Y') ? PR_TRUE : PR_FALSE)); + +} + +static SECStatus +AddSubjectAltNames(void *extHandle, const char *names, CERTGeneralNameType type) +{ + SECItem item = { 0, NULL, 0 }; + CERTGeneralName *nameList = NULL; + CERTGeneralName *current = NULL; + PRCList *prev = NULL; + PRArenaPool *arena; + const char *cp; + char *tbuf; + SECStatus rv = SECSuccess; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + return SECFailure; + } + + /* + * walk down the comma separated list of names. NOTE: there is + * no sanity checks to see if the email address look like email addresses. + */ + for (cp=names; cp; cp = PORT_Strchr(cp,',')) { + int len; + char *end; + + if (*cp == ',') { + cp++; + } + end = PORT_Strchr(cp,','); + len = end ? end-cp : PORT_Strlen(cp); + if (len <= 0) { + continue; + } + tbuf = PORT_ArenaAlloc(arena,len+1); + PORT_Memcpy(tbuf,cp,len); + tbuf[len] = 0; + current = (CERTGeneralName *) PORT_ZAlloc(sizeof(CERTGeneralName)); + if (!current) { + rv = SECFailure; + break; + } + if (prev) { + current->l.prev = prev; + prev->next = &(current->l); + } else { + nameList = current; + } + current->type = type; + current->type = certRFC822Name; + current->name.other.data = (unsigned char *)tbuf; + current->name.other.len = PORT_Strlen(tbuf); + prev = &(current->l); + } + if (rv != SECSuccess) { + goto loser; + } + /* no email address */ + if (!nameList) { + /*rv=SECSuccess; We know rv is SECSuccess because of the previous if*/ + goto done; + } + nameList->l.prev = prev; + current->l.next = &(nameList->l); + + CERT_EncodeAltNameExtension(arena, nameList, &item); + rv = CERT_AddExtension (extHandle, SEC_OID_X509_SUBJECT_ALT_NAME, &item, + PR_FALSE, PR_TRUE); +done: +loser: + PORT_FreeArena(arena, PR_FALSE); + return rv; + +} + +static SECStatus +AddEmailSubjectAlt(void *extHandle, const char *emailAddrs) +{ + return AddSubjectAltNames(extHandle, emailAddrs, certRFC822Name); +} + +static SECStatus +AddDNSSubjectAlt(void *extHandle, const char *dnsNames) +{ + return AddSubjectAltNames(extHandle, dnsNames, certDNSName); +} + + +typedef SECStatus (* EXTEN_VALUE_ENCODER) + (PRArenaPool *extHandle, void *value, SECItem *encodedValue); + +static SECStatus +EncodeAndAddExtensionValue( + PRArenaPool * arena, + void * extHandle, + void * value, + PRBool criticality, + int extenType, + EXTEN_VALUE_ENCODER EncodeValueFn) +{ + SECItem encodedValue; + SECStatus rv; + + + encodedValue.data = NULL; + encodedValue.len = 0; + do { + rv = (*EncodeValueFn)(arena, value, &encodedValue); + if (rv != SECSuccess) + break; + + rv = CERT_AddExtension + (extHandle, extenType, &encodedValue, criticality,PR_TRUE); + } while (0); + + return (rv); +} + +static SECStatus +AddBasicConstraint(void *extHandle) +{ + CERTBasicConstraints basicConstraint; + SECItem encodedValue; + SECStatus rv; + char buffer[10]; + + encodedValue.data = NULL; + encodedValue.len = 0; + do { + basicConstraint.pathLenConstraint = CERT_UNLIMITED_PATH_CONSTRAINT; + puts ("Is this a CA certificate [y/n]?"); + gets (buffer); + basicConstraint.isCA = (buffer[0] == 'Y' || buffer[0] == 'y') ? + PR_TRUE : PR_FALSE; + + puts ("Enter the path length constraint, enter to skip [<0 for unlimited path]:"); + gets (buffer); + if (PORT_Strlen (buffer) > 0) + basicConstraint.pathLenConstraint = atoi (buffer); + + rv = CERT_EncodeBasicConstraintValue (NULL, &basicConstraint, &encodedValue); + if (rv) + return (rv); + + buffer[0] = 'n'; + puts ("Is this a critical extension [y/n]? "); + gets (buffer); + rv = CERT_AddExtension + (extHandle, SEC_OID_X509_BASIC_CONSTRAINTS, + &encodedValue, (buffer[0] == 'y' || buffer[0] == 'Y') ? + PR_TRUE : PR_FALSE ,PR_TRUE); + } while (0); + PORT_Free (encodedValue.data); + return (rv); +} + +static SECItem * +SignCert(CERTCertDBHandle *handle, CERTCertificate *cert, PRBool selfsign, + SECOidTag hashAlgTag, + SECKEYPrivateKey *privKey, char *issuerNickName, void *pwarg) +{ + SECItem der; + SECItem *result = NULL; + SECKEYPrivateKey *caPrivateKey = NULL; + SECStatus rv; + PRArenaPool *arena; + SECOidTag algID; + void *dummy; + + if( !selfsign ) { + CERTCertificate *issuer = PK11_FindCertFromNickname(issuerNickName, pwarg); + if( (CERTCertificate *)NULL == issuer ) { + SECU_PrintError(progName, "unable to find issuer with nickname %s", + issuerNickName); + return (SECItem *)NULL; + } + + privKey = caPrivateKey = PK11_FindKeyByAnyCert(issuer, pwarg); + CERT_DestroyCertificate(issuer); + if (caPrivateKey == NULL) { + SECU_PrintError(progName, "unable to retrieve key %s", issuerNickName); + return NULL; + } + } + + arena = cert->arena; + + algID = getSignatureOidTag(privKey->keyType, hashAlgTag); + if (algID == SEC_OID_UNKNOWN) { + fprintf(stderr, "Unknown key or hash type for issuer."); + goto done; + } + + rv = SECOID_SetAlgorithmID(arena, &cert->signature, algID, 0); + if (rv != SECSuccess) { + fprintf(stderr, "Could not set signature algorithm id."); + goto done; + } + + /* we only deal with cert v3 here */ + *(cert->version.data) = 2; + cert->version.len = 1; + + der.len = 0; + der.data = NULL; + dummy = SEC_ASN1EncodeItem (arena, &der, cert, + SEC_ASN1_GET(CERT_CertificateTemplate)); + if (!dummy) { + fprintf (stderr, "Could not encode certificate.\n"); + goto done; + } + + result = (SECItem *) PORT_ArenaZAlloc (arena, sizeof (SECItem)); + if (result == NULL) { + fprintf (stderr, "Could not allocate item for certificate data.\n"); + goto done; + } + + rv = SEC_DerSignData(arena, result, der.data, der.len, privKey, algID); + if (rv != SECSuccess) { + fprintf (stderr, "Could not sign encoded certificate data.\n"); + PORT_Free(result); + result = NULL; + goto done; + } + cert->derCert = *result; +done: + if (caPrivateKey) { + SECKEY_DestroyPrivateKey(caPrivateKey); + } + return result; +} + +static SECStatus +AddAuthKeyID (void *extHandle) +{ + CERTAuthKeyID *authKeyID = NULL; + PRArenaPool *arena = NULL; + SECStatus rv = SECSuccess; + char buffer[512]; + + do { + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) { + SECU_PrintError(progName, "out of memory"); + GEN_BREAK (SECFailure); + } + + if (GetYesNo ("Enter value for the authKeyID extension [y/n]?\n") == 0) + break; + + authKeyID = PORT_ArenaZAlloc (arena, sizeof (CERTAuthKeyID)); + if (authKeyID == NULL) { + GEN_BREAK (SECFailure); + } + + rv = GetString (arena, "Enter value for the key identifier fields, enter to omit:", + &authKeyID->keyID); + if (rv != SECSuccess) + break; + authKeyID->authCertIssuer = GetGeneralName (arena); + if (authKeyID->authCertIssuer == NULL && SECFailure == PORT_GetError ()) + break; + + + rv = GetString (arena, "Enter value for the authCertSerial field, enter to omit:", + &authKeyID->authCertSerialNumber); + + buffer[0] = 'n'; + puts ("Is this a critical extension [y/n]? "); + gets (buffer); + + rv = EncodeAndAddExtensionValue + (arena, extHandle, authKeyID, + (buffer[0] == 'y' || buffer[0] == 'Y') ? PR_TRUE : PR_FALSE, + SEC_OID_X509_AUTH_KEY_ID, + (EXTEN_VALUE_ENCODER) CERT_EncodeAuthKeyID); + if (rv) + break; + + } while (0); + if (arena) + PORT_FreeArena (arena, PR_FALSE); + return (rv); +} + +static SECStatus +AddCrlDistPoint(void *extHandle) +{ + PRArenaPool *arena = NULL; + CERTCrlDistributionPoints *crlDistPoints = NULL; + CRLDistributionPoint *current; + SECStatus rv = SECSuccess; + int count = 0, intValue; + char buffer[5]; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) + return (SECFailure); + + do { + current = NULL; + current = PORT_ArenaZAlloc (arena, sizeof (*current)); + if (current == NULL) { + GEN_BREAK (SECFailure); + } + + /* Get the distributionPointName fields - this field is optional */ + puts ("Enter the type of the distribution point name:\n"); + puts ("\t1 - Full Name\n\t2 - Relative Name\n\tOther - omit\n\t\tChoice: "); + scanf ("%d", &intValue); + switch (intValue) { + case generalName: + current->distPointType = intValue; + current->distPoint.fullName = GetGeneralName (arena); + rv = PORT_GetError(); + break; + + case relativeDistinguishedName: { + CERTName *name; + char buffer[512]; + + current->distPointType = intValue; + puts ("Enter the relative name: "); + fflush (stdout); + gets (buffer); + /* For simplicity, use CERT_AsciiToName to converse from a string + to NAME, but we only interest in the first RDN */ + name = CERT_AsciiToName (buffer); + if (!name) { + GEN_BREAK (SECFailure); + } + rv = CERT_CopyRDN (arena, ¤t->distPoint.relativeName, name->rdns[0]); + CERT_DestroyName (name); + break; + } + } + if (rv != SECSuccess) + break; + + /* Get the reason flags */ + puts ("\nSelect one of the following for the reason flags\n"); + puts ("\t0 - unused\n\t1 - keyCompromise\n\t2 - caCompromise\n\t3 - affiliationChanged\n"); + puts ("\t4 - superseded\n\t5 - cessationOfOperation\n\t6 - certificateHold\n"); + puts ("\tother - omit\t\tChoice: "); + + scanf ("%d", &intValue); + if (intValue >= 0 && intValue <8) { + current->reasons.data = PORT_ArenaAlloc (arena, sizeof(char)); + if (current->reasons.data == NULL) { + GEN_BREAK (SECFailure); + } + *current->reasons.data = (char)(0x80 >> intValue); + current->reasons.len = 1; + } + puts ("Enter value for the CRL Issuer name:\n"); + current->crlIssuer = GetGeneralName (arena); + if (current->crlIssuer == NULL && (rv = PORT_GetError()) == SECFailure) + break; + + if (crlDistPoints == NULL) { + crlDistPoints = PORT_ArenaZAlloc (arena, sizeof (*crlDistPoints)); + if (crlDistPoints == NULL) { + GEN_BREAK (SECFailure); + } + } + + crlDistPoints->distPoints = PORT_ArenaGrow (arena, + crlDistPoints->distPoints, + sizeof (*crlDistPoints->distPoints) * count, + sizeof (*crlDistPoints->distPoints) *(count + 1)); + if (crlDistPoints->distPoints == NULL) { + GEN_BREAK (SECFailure); + } + + crlDistPoints->distPoints[count] = current; + ++count; + if (GetYesNo ("Enter more value for the CRL distribution point extension [y/n]\n") == 0) { + /* Add null to the end of the crlDistPoints to mark end of data */ + crlDistPoints->distPoints = PORT_ArenaGrow(arena, + crlDistPoints->distPoints, + sizeof (*crlDistPoints->distPoints) * count, + sizeof (*crlDistPoints->distPoints) *(count + 1)); + crlDistPoints->distPoints[count] = NULL; + break; + } + + + } while (1); + + if (rv == SECSuccess) { + buffer[0] = 'n'; + puts ("Is this a critical extension [y/n]? "); + gets (buffer); + + rv = EncodeAndAddExtensionValue(arena, extHandle, crlDistPoints, + (buffer[0] == 'Y' || buffer[0] == 'y') ? PR_TRUE : PR_FALSE, + SEC_OID_X509_CRL_DIST_POINTS, + (EXTEN_VALUE_ENCODER) CERT_EncodeCRLDistributionPoints); + } + if (arena) + PORT_FreeArena (arena, PR_FALSE); + return (rv); +} + +static SECStatus +CreateCert( + CERTCertDBHandle *handle, + char * issuerNickName, + PRFileDesc *inFile, + PRFileDesc *outFile, + SECKEYPrivateKey *selfsignprivkey, + void *pwarg, + SECOidTag hashAlgTag, + unsigned int serialNumber, + int warpmonths, + int validitylength, + const char *emailAddrs, + const char *dnsNames, + PRBool ascii, + PRBool selfsign, + PRBool keyUsage, + PRBool extKeyUsage, + PRBool basicConstraint, + PRBool authKeyID, + PRBool crlDistPoints, + PRBool nscpCertType) +{ + void * extHandle; + SECItem * certDER; + PRArenaPool *arena = NULL; + CERTCertificate *subjectCert = NULL; + CERTCertificateRequest *certReq = NULL; + SECStatus rv = SECSuccess; + SECItem reqDER; + + reqDER.data = NULL; + do { + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!arena) { + GEN_BREAK (SECFailure); + } + + /* Create a certrequest object from the input cert request der */ + certReq = GetCertRequest(inFile, ascii); + if (certReq == NULL) { + GEN_BREAK (SECFailure) + } + + subjectCert = MakeV1Cert (handle, certReq, issuerNickName, selfsign, + serialNumber, warpmonths, validitylength); + if (subjectCert == NULL) { + GEN_BREAK (SECFailure) + } + + extHandle = CERT_StartCertExtensions (subjectCert); + if (extHandle == NULL) { + GEN_BREAK (SECFailure) + } + + /* Add key usage extension */ + if (keyUsage) { + rv = AddKeyUsage(extHandle); + if (rv) + break; + } + + /* Add extended key usage extension */ + if (extKeyUsage) { + rv = AddExtKeyUsage(extHandle); + if (rv) + break; + } + + /* Add basic constraint extension */ + if (basicConstraint) { + rv = AddBasicConstraint(extHandle); + if (rv) + break; + } + + if (authKeyID) { + rv = AddAuthKeyID (extHandle); + if (rv) + break; + } + + + if (crlDistPoints) { + rv = AddCrlDistPoint (extHandle); + if (rv) + break; + } + + if (nscpCertType) { + rv = AddNscpCertType(extHandle); + if (rv) + break; + } + + if (emailAddrs != NULL) { + rv = AddEmailSubjectAlt(extHandle,emailAddrs); + if (rv) + break; + } + + if (dnsNames != NULL) { + rv = AddDNSSubjectAlt(extHandle,dnsNames); + if (rv) + break; + } + + CERT_FinishExtensions(extHandle); + + certDER = SignCert(handle, subjectCert, selfsign, hashAlgTag, + selfsignprivkey, issuerNickName,pwarg); + + if (certDER) { + if (ascii) { + PR_fprintf(outFile, "%s\n%s\n%s\n", NS_CERT_HEADER, + BTOA_DataToAscii(certDER->data, certDER->len), + NS_CERT_TRAILER); + } else { + PR_Write(outFile, certDER->data, certDER->len); + } + } + + } while (0); + CERT_DestroyCertificateRequest (certReq); + CERT_DestroyCertificate (subjectCert); + PORT_FreeArena (arena, PR_FALSE); + if (rv != SECSuccess) { + PRErrorCode perr = PR_GetError(); + fprintf(stderr, "%s: unable to create cert (%s)\n", progName, + SECU_Strerror(perr)); + } + return (rv); +} + +/* Certutil commands */ +enum { + cmd_AddCert = 0, + cmd_CreateNewCert, + cmd_DeleteCert, + cmd_AddEmailCert, + cmd_DeleteKey, + cmd_GenKeyPair, + cmd_PrintHelp, + cmd_ListKeys, + cmd_ListCerts, + cmd_ModifyCertTrust, + cmd_NewDBs, + cmd_DumpChain, + cmd_CertReq, + cmd_CreateAndAddCert, + cmd_TokenReset, + cmd_ListModules, + cmd_CheckCertValidity, + cmd_ChangePassword, + cmd_Version +}; + +/* Certutil options */ +enum { + opt_SSOPass = 0, + opt_AddKeyUsageExt, + opt_AddBasicConstraintExt, + opt_AddAuthorityKeyIDExt, + opt_AddCRLDistPtsExt, + opt_AddNSCertTypeExt, + opt_AddExtKeyUsageExt, + opt_ExtendedEmailAddrs, + opt_ExtendedDNSNames, + opt_ASCIIForIO, + opt_ValidityTime, + opt_IssuerName, + opt_CertDir, + opt_VerifySig, + opt_PasswordFile, + opt_KeySize, + opt_TokenName, + opt_InputFile, + opt_KeyIndex, + opt_KeyType, + opt_DetailedInfo, + opt_SerialNumber, + opt_Nickname, + opt_OutputFile, + opt_PhoneNumber, + opt_DBPrefix, + opt_PQGFile, + opt_BinaryDER, + opt_Subject, + opt_Trust, + opt_Usage, + opt_Validity, + opt_OffsetMonths, + opt_SelfSign, + opt_RW, + opt_Exponent, + opt_NoiseFile, + opt_Hash +}; + +static secuCommandFlag certutil_commands[] = +{ + { /* cmd_AddCert */ 'A', PR_FALSE, 0, PR_FALSE }, + { /* cmd_CreateNewCert */ 'C', PR_FALSE, 0, PR_FALSE }, + { /* cmd_DeleteCert */ 'D', PR_FALSE, 0, PR_FALSE }, + { /* cmd_AddEmailCert */ 'E', PR_FALSE, 0, PR_FALSE }, + { /* cmd_DeleteKey */ 'F', PR_FALSE, 0, PR_FALSE }, + { /* cmd_GenKeyPair */ 'G', PR_FALSE, 0, PR_FALSE }, + { /* cmd_PrintHelp */ 'H', PR_FALSE, 0, PR_FALSE }, + { /* cmd_ListKeys */ 'K', PR_FALSE, 0, PR_FALSE }, + { /* cmd_ListCerts */ 'L', PR_FALSE, 0, PR_FALSE }, + { /* cmd_ModifyCertTrust */ 'M', PR_FALSE, 0, PR_FALSE }, + { /* cmd_NewDBs */ 'N', PR_FALSE, 0, PR_FALSE }, + { /* cmd_DumpChain */ 'O', PR_FALSE, 0, PR_FALSE }, + { /* cmd_CertReq */ 'R', PR_FALSE, 0, PR_FALSE }, + { /* cmd_CreateAndAddCert */ 'S', PR_FALSE, 0, PR_FALSE }, + { /* cmd_TokenReset */ 'T', PR_FALSE, 0, PR_FALSE }, + { /* cmd_ListModules */ 'U', PR_FALSE, 0, PR_FALSE }, + { /* cmd_CheckCertValidity */ 'V', PR_FALSE, 0, PR_FALSE }, + { /* cmd_ChangePassword */ 'W', PR_FALSE, 0, PR_FALSE }, + { /* cmd_Version */ 'Y', PR_FALSE, 0, PR_FALSE } +}; + +static secuCommandFlag certutil_options[] = +{ + { /* opt_SSOPass */ '0', PR_TRUE, 0, PR_FALSE }, + { /* opt_AddKeyUsageExt */ '1', PR_FALSE, 0, PR_FALSE }, + { /* opt_AddBasicConstraintExt*/ '2', PR_FALSE, 0, PR_FALSE }, + { /* opt_AddAuthorityKeyIDExt*/ '3', PR_FALSE, 0, PR_FALSE }, + { /* opt_AddCRLDistPtsExt */ '4', PR_FALSE, 0, PR_FALSE }, + { /* opt_AddNSCertTypeExt */ '5', PR_FALSE, 0, PR_FALSE }, + { /* opt_AddExtKeyUsageExt */ '6', PR_FALSE, 0, PR_FALSE }, + { /* opt_ExtendedEmailAddrs */ '7', PR_TRUE, 0, PR_FALSE }, + { /* opt_ExtendedDNSNames */ '8', PR_TRUE, 0, PR_FALSE }, + { /* opt_ASCIIForIO */ 'a', PR_FALSE, 0, PR_FALSE }, + { /* opt_ValidityTime */ 'b', PR_TRUE, 0, PR_FALSE }, + { /* opt_IssuerName */ 'c', PR_TRUE, 0, PR_FALSE }, + { /* opt_CertDir */ 'd', PR_TRUE, 0, PR_FALSE }, + { /* opt_VerifySig */ 'e', PR_FALSE, 0, PR_FALSE }, + { /* opt_PasswordFile */ 'f', PR_TRUE, 0, PR_FALSE }, + { /* opt_KeySize */ 'g', PR_TRUE, 0, PR_FALSE }, + { /* opt_TokenName */ 'h', PR_TRUE, 0, PR_FALSE }, + { /* opt_InputFile */ 'i', PR_TRUE, 0, PR_FALSE }, + { /* opt_KeyIndex */ 'j', PR_TRUE, 0, PR_FALSE }, + { /* opt_KeyType */ 'k', PR_TRUE, 0, PR_FALSE }, + { /* opt_DetailedInfo */ 'l', PR_FALSE, 0, PR_FALSE }, + { /* opt_SerialNumber */ 'm', PR_TRUE, 0, PR_FALSE }, + { /* opt_Nickname */ 'n', PR_TRUE, 0, PR_FALSE }, + { /* opt_OutputFile */ 'o', PR_TRUE, 0, PR_FALSE }, + { /* opt_PhoneNumber */ 'p', PR_TRUE, 0, PR_FALSE }, + { /* opt_DBPrefix */ 'P', PR_TRUE, 0, PR_FALSE }, + { /* opt_PQGFile */ 'q', PR_TRUE, 0, PR_FALSE }, + { /* opt_BinaryDER */ 'r', PR_FALSE, 0, PR_FALSE }, + { /* opt_Subject */ 's', PR_TRUE, 0, PR_FALSE }, + { /* opt_Trust */ 't', PR_TRUE, 0, PR_FALSE }, + { /* opt_Usage */ 'u', PR_TRUE, 0, PR_FALSE }, + { /* opt_Validity */ 'v', PR_TRUE, 0, PR_FALSE }, + { /* opt_OffsetMonths */ 'w', PR_TRUE, 0, PR_FALSE }, + { /* opt_SelfSign */ 'x', PR_FALSE, 0, PR_FALSE }, + { /* opt_RW */ 'X', PR_FALSE, 0, PR_FALSE }, + { /* opt_Exponent */ 'y', PR_TRUE, 0, PR_FALSE }, + { /* opt_NoiseFile */ 'z', PR_TRUE, 0, PR_FALSE }, + { /* opt_Hash */ 'Z', PR_TRUE, 0, PR_FALSE } +}; + +int +main(int argc, char **argv) +{ + CERTCertDBHandle *certHandle; + PK11SlotInfo *slot = NULL; + CERTName * subject = 0; + PRFileDesc *inFile = PR_STDIN; + PRFileDesc *outFile = 0; + char * certfile = "tempcert"; + char * certreqfile = "tempcertreq"; + char * slotname = "internal"; + char * certPrefix = ""; + KeyType keytype = rsaKey; + char * name = NULL; + SECOidTag hashAlgTag = SEC_OID_UNKNOWN; + int keysize = DEFAULT_KEY_BITS; + int publicExponent = 0x010001; + unsigned int serialNumber = 0; + int warpmonths = 0; + int validitylength = 0; + int commandsEntered = 0; + char commandToRun = '\0'; + secuPWData pwdata = { PW_NONE, 0 }; + PRBool readOnly = PR_FALSE; + + SECKEYPrivateKey *privkey = NULL; + SECKEYPublicKey *pubkey = NULL; + + int i; + SECStatus rv; + + secuCommand certutil; + certutil.numCommands = sizeof(certutil_commands) / sizeof(secuCommandFlag); + certutil.numOptions = sizeof(certutil_options) / sizeof(secuCommandFlag); + certutil.commands = certutil_commands; + certutil.options = certutil_options; + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + rv = SECU_ParseCommandLine(argc, argv, progName, &certutil); + + if (rv != SECSuccess) + Usage(progName); + + if (certutil.commands[cmd_PrintHelp].activated) + LongUsage(progName); + + if (certutil.options[opt_PasswordFile].arg) { + pwdata.source = PW_FROMFILE; + pwdata.data = certutil.options[opt_PasswordFile].arg; + } + + if (certutil.options[opt_CertDir].activated) + SECU_ConfigDirectory(certutil.options[opt_CertDir].arg); + + if (certutil.options[opt_KeySize].activated) { + keysize = PORT_Atoi(certutil.options[opt_KeySize].arg); + if ((keysize < MIN_KEY_BITS) || (keysize > MAX_KEY_BITS)) { + PR_fprintf(PR_STDERR, + "%s -g: Keysize must be between %d and %d.\n", + MIN_KEY_BITS, MAX_KEY_BITS); + return 255; + } + } + + /* -h specify token name */ + if (certutil.options[opt_TokenName].activated) { + if (PL_strcmp(certutil.options[opt_TokenName].arg, "all") == 0) + slotname = NULL; + else + slotname = PL_strdup(certutil.options[opt_TokenName].arg); + } + + /* -Z hash type */ + if (certutil.options[opt_Hash].activated) { + char * arg = certutil.options[opt_Hash].arg; + if (!PL_strcmp(arg, "MD2")) { + hashAlgTag = SEC_OID_MD2; + } else if (!PL_strcmp(arg, "MD4")) { + hashAlgTag = SEC_OID_MD4; + } else if (!PL_strcmp(arg, "MD5")) { + hashAlgTag = SEC_OID_MD5; + } else if (!PL_strcmp(arg, "SHA1")) { + hashAlgTag = SEC_OID_SHA1; + } else if (!PL_strcmp(arg, "SHA256")) { + hashAlgTag = SEC_OID_SHA256; + } else if (!PL_strcmp(arg, "SHA384")) { + hashAlgTag = SEC_OID_SHA384; + } else if (!PL_strcmp(arg, "SHA512")) { + hashAlgTag = SEC_OID_SHA512; + } else { + PR_fprintf(PR_STDERR, "%s -Z: %s is not a recognized type.\n", + progName, arg); + return 255; + } + } + + /* -k key type */ + if (certutil.options[opt_KeyType].activated) { + char * arg = certutil.options[opt_KeyType].arg; + if (PL_strcmp(arg, "rsa") == 0) { + keytype = rsaKey; + } else if (PL_strcmp(arg, "dsa") == 0) { + keytype = dsaKey; + } else if (PL_strcmp(arg, "all") == 0) { + keytype = nullKey; + } else { + PR_fprintf(PR_STDERR, "%s -k: %s is not a recognized type.\n", + progName, arg); + return 255; + } + } + + /* -m serial number */ + if (certutil.options[opt_SerialNumber].activated) { + int sn = PORT_Atoi(certutil.options[opt_SerialNumber].arg); + if (sn < 0) { + PR_fprintf(PR_STDERR, "%s -m: %s is not a valid serial number.\n", + progName, certutil.options[opt_SerialNumber].arg); + return 255; + } + serialNumber = sn; + } + + /* -P certdb name prefix */ + if (certutil.options[opt_DBPrefix].activated) + certPrefix = strdup(certutil.options[opt_DBPrefix].arg); + + /* -q PQG file */ + if (certutil.options[opt_PQGFile].activated) { + if (keytype != dsaKey) { + PR_fprintf(PR_STDERR, "%s -q: PQG file is for DSA key (-k dsa).\n)", + progName); + return 255; + } + } + + /* -s subject name */ + if (certutil.options[opt_Subject].activated) { + subject = CERT_AsciiToName(certutil.options[opt_Subject].arg); + if (!subject) { + PR_fprintf(PR_STDERR, "%s -s: improperly formatted name: \"%s\"\n", + progName, certutil.options[opt_Subject].arg); + return 255; + } + } + + /* -v validity period */ + if (certutil.options[opt_Validity].activated) { + validitylength = PORT_Atoi(certutil.options[opt_Validity].arg); + if (validitylength < 0) { + PR_fprintf(PR_STDERR, "%s -v: incorrect validity period: \"%s\"\n", + progName, certutil.options[opt_Validity].arg); + return 255; + } + } + + /* -w warp months */ + if (certutil.options[opt_OffsetMonths].activated) + warpmonths = PORT_Atoi(certutil.options[opt_OffsetMonths].arg); + + /* -y public exponent (for RSA) */ + if (certutil.options[opt_Exponent].activated) { + publicExponent = PORT_Atoi(certutil.options[opt_Exponent].arg); + if ((publicExponent != 3) && + (publicExponent != 17) && + (publicExponent != 65537)) { + PR_fprintf(PR_STDERR, "%s -y: incorrect public exponent %d.", + progName, publicExponent); + PR_fprintf(PR_STDERR, "Must be 3, 17, or 65537.\n"); + return 255; + } + } + + /* Check number of commands entered. */ + commandsEntered = 0; + for (i=0; i< certutil.numCommands; i++) { + if (certutil.commands[i].activated) { + commandToRun = certutil.commands[i].flag; + commandsEntered++; + } + if (commandsEntered > 1) + break; + } + if (commandsEntered > 1) { + PR_fprintf(PR_STDERR, "%s: only one command at a time!\n", progName); + PR_fprintf(PR_STDERR, "You entered: "); + for (i=0; i< certutil.numCommands; i++) { + if (certutil.commands[i].activated) + PR_fprintf(PR_STDERR, " -%c", certutil.commands[i].flag); + } + PR_fprintf(PR_STDERR, "\n"); + return 255; + } + if (commandsEntered == 0) { + PR_fprintf(PR_STDERR, "%s: you must enter a command!\n", progName); + Usage(progName); + } + + if (certutil.commands[cmd_ListCerts].activated || + certutil.commands[cmd_PrintHelp].activated || + certutil.commands[cmd_ListKeys].activated || + certutil.commands[cmd_ListModules].activated || + certutil.commands[cmd_CheckCertValidity].activated || + certutil.commands[cmd_Version].activated ) { + readOnly = !certutil.options[opt_RW].activated; + } + + /* -A, -D, -F, -M, -S, -V, and all require -n */ + if ((certutil.commands[cmd_AddCert].activated || + certutil.commands[cmd_DeleteCert].activated || + certutil.commands[cmd_DeleteKey].activated || + certutil.commands[cmd_ModifyCertTrust].activated || + certutil.commands[cmd_CreateAndAddCert].activated || + certutil.commands[cmd_CheckCertValidity].activated) && + !certutil.options[opt_Nickname].activated) { + PR_fprintf(PR_STDERR, + "%s -%c: nickname is required for this command (-n).\n", + progName, commandToRun); + return 255; + } + + /* -A, -E, -M, -S require trust */ + if ((certutil.commands[cmd_AddCert].activated || + certutil.commands[cmd_AddEmailCert].activated || + certutil.commands[cmd_ModifyCertTrust].activated || + certutil.commands[cmd_CreateAndAddCert].activated) && + !certutil.options[opt_Trust].activated) { + PR_fprintf(PR_STDERR, + "%s -%c: trust is required for this command (-t).\n", + progName, commandToRun); + return 255; + } + + /* if -L is given raw or ascii mode, it must be for only one cert. */ + if (certutil.commands[cmd_ListCerts].activated && + (certutil.options[opt_ASCIIForIO].activated || + certutil.options[opt_BinaryDER].activated) && + !certutil.options[opt_Nickname].activated) { + PR_fprintf(PR_STDERR, + "%s: nickname is required to dump cert in raw or ascii mode.\n", + progName); + return 255; + } + + /* -L can only be in (raw || ascii). */ + if (certutil.commands[cmd_ListCerts].activated && + certutil.options[opt_ASCIIForIO].activated && + certutil.options[opt_BinaryDER].activated) { + PR_fprintf(PR_STDERR, + "%s: cannot specify both -r and -a when dumping cert.\n", + progName); + return 255; + } + + /* For now, deny -C -x combination */ + if (certutil.commands[cmd_CreateNewCert].activated && + certutil.options[opt_SelfSign].activated) { + PR_fprintf(PR_STDERR, + "%s: self-signing a cert request is not supported.\n", + progName); + return 255; + } + + /* If making a cert request, need a subject. */ + if ((certutil.commands[cmd_CertReq].activated || + certutil.commands[cmd_CreateAndAddCert].activated) && + !certutil.options[opt_Subject].activated) { + PR_fprintf(PR_STDERR, + "%s -%c: subject is required to create a cert request.\n", + progName, commandToRun); + return 255; + } + + /* If making a cert, need a serial number. */ + if ((certutil.commands[cmd_CreateNewCert].activated || + certutil.commands[cmd_CreateAndAddCert].activated) && + !certutil.options[opt_SerialNumber].activated) { + /* Make a default serial number from the current time. */ + PRTime now = PR_Now(); + LL_USHR(now, now, 19); + LL_L2UI(serialNumber, now); + } + + /* Validation needs the usage to validate for. */ + if (certutil.commands[cmd_CheckCertValidity].activated && + !certutil.options[opt_Usage].activated) { + PR_fprintf(PR_STDERR, + "%s -V: specify a usage to validate the cert for (-u).\n", + progName); + return 255; + } + + /* To make a cert, need either a issuer or to self-sign it. */ + if (certutil.commands[cmd_CreateAndAddCert].activated && + !(certutil.options[opt_IssuerName].activated || + certutil.options[opt_SelfSign].activated)) { + PR_fprintf(PR_STDERR, + "%s -S: must specify issuer (-c) or self-sign (-x).\n", + progName); + return 255; + } + + /* Using slotname == NULL for listing keys and certs on all slots, + * but only that. */ + if (!(certutil.commands[cmd_ListKeys].activated || + certutil.commands[cmd_DumpChain].activated || + certutil.commands[cmd_ListCerts].activated) && slotname == NULL) { + PR_fprintf(PR_STDERR, + "%s -%c: cannot use \"-h all\" for this command.\n", + progName, commandToRun); + return 255; + } + + /* Using keytype == nullKey for list all key types, but only that. */ + if (!certutil.commands[cmd_ListKeys].activated && keytype == nullKey) { + PR_fprintf(PR_STDERR, + "%s -%c: cannot use \"-k all\" for this command.\n", + progName, commandToRun); + return 255; + } + + /* -S open outFile, temporary file for cert request. */ + if (certutil.commands[cmd_CreateAndAddCert].activated) { + outFile = PR_Open(certreqfile, PR_RDWR | PR_CREATE_FILE, 00660); + if (!outFile) { + PR_fprintf(PR_STDERR, + "%s -o: unable to open \"%s\" for writing (%ld, %ld)\n", + progName, certreqfile, + PR_GetError(), PR_GetOSError()); + return 255; + } + } + + /* Open the input file. */ + if (certutil.options[opt_InputFile].activated) { + inFile = PR_Open(certutil.options[opt_InputFile].arg, PR_RDONLY, 0); + if (!inFile) { + PR_fprintf(PR_STDERR, + "%s: unable to open \"%s\" for reading (%ld, %ld).\n", + progName, certutil.options[opt_InputFile].arg, + PR_GetError(), PR_GetOSError()); + return 255; + } + } + + /* Open the output file. */ + if (certutil.options[opt_OutputFile].activated && !outFile) { + outFile = PR_Open(certutil.options[opt_OutputFile].arg, + PR_CREATE_FILE | PR_RDWR, 00660); + if (!outFile) { + PR_fprintf(PR_STDERR, + "%s: unable to open \"%s\" for writing (%ld, %ld).\n", + progName, certutil.options[opt_OutputFile].arg, + PR_GetError(), PR_GetOSError()); + return 255; + } + } + + name = SECU_GetOptionArg(&certutil, opt_Nickname); + + PK11_SetPasswordFunc(SECU_GetModulePassword); + + /* Initialize NSPR and NSS. */ + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + rv = NSS_Initialize(SECU_ConfigDirectory(NULL), certPrefix, certPrefix, + "secmod.db", readOnly ? NSS_INIT_READONLY: 0); + if (rv != SECSuccess) { + SECU_PrintPRandOSError(progName); + rv = SECFailure; + goto shutdown; + } + certHandle = CERT_GetDefaultCertDB(); + + if (certutil.commands[cmd_Version].activated) { + int version = CERT_GetDBContentVersion(certHandle); + printf("Certificate database content version: %d\n", version); + } + + if (PL_strcmp(slotname, "internal") == 0) + slot = PK11_GetInternalKeySlot(); + else if (slotname != NULL) + slot = PK11_FindSlotByName(slotname); + + /* If creating new database, initialize the password. */ + if (certutil.commands[cmd_NewDBs].activated) { + SECU_ChangePW(slot, 0, certutil.options[opt_PasswordFile].arg); + } + + /* The following 8 options are mutually exclusive with all others. */ + + /* List certs (-L) */ + if (certutil.commands[cmd_ListCerts].activated) { + rv = ListCerts(certHandle, name, slot, + certutil.options[opt_BinaryDER].activated, + certutil.options[opt_ASCIIForIO].activated, + (outFile) ? outFile : PR_STDOUT, &pwdata); + goto shutdown; + } + if (certutil.commands[cmd_DumpChain].activated) { + rv = DumpChain(certHandle, name); + goto shutdown; + } + /* XXX needs work */ + /* List keys (-K) */ + if (certutil.commands[cmd_ListKeys].activated) { + rv = ListKeys(slot, name, 0 /*keyindex*/, keytype, PR_FALSE /*dopriv*/, + &pwdata); + goto shutdown; + } + /* List modules (-U) */ + if (certutil.commands[cmd_ListModules].activated) { + rv = ListModules(); + goto shutdown; + } + /* Delete cert (-D) */ + if (certutil.commands[cmd_DeleteCert].activated) { + rv = DeleteCert(certHandle, name); + goto shutdown; + } + /* Delete key (-F) */ + if (certutil.commands[cmd_DeleteKey].activated) { + rv = DeleteKey(name, &pwdata); + goto shutdown; + } + /* Modify trust attribute for cert (-M) */ + if (certutil.commands[cmd_ModifyCertTrust].activated) { + rv = ChangeTrustAttributes(certHandle, name, + certutil.options[opt_Trust].arg); + goto shutdown; + } + /* Change key db password (-W) (future - change pw to slot?) */ + if (certutil.commands[cmd_ChangePassword].activated) { + rv = SECU_ChangePW(slot, 0, certutil.options[opt_PasswordFile].arg); + goto shutdown; + } + /* Reset the a token */ + if (certutil.commands[cmd_TokenReset].activated) { + char *sso_pass = ""; + + if (certutil.options[opt_SSOPass].activated) { + sso_pass = certutil.options[opt_SSOPass].arg; + } + rv = PK11_ResetToken(slot,sso_pass); + + goto shutdown; + } + /* Check cert validity against current time (-V) */ + if (certutil.commands[cmd_CheckCertValidity].activated) { + /* XXX temporary hack for fips - must log in to get priv key */ + if (certutil.options[opt_VerifySig].activated) { + if (slot && PK11_NeedLogin(slot)) + PK11_Authenticate(slot, PR_TRUE, &pwdata); + } + rv = ValidateCert(certHandle, name, + certutil.options[opt_ValidityTime].arg, + certutil.options[opt_Usage].arg, + certutil.options[opt_VerifySig].activated, + certutil.options[opt_DetailedInfo].activated, + &pwdata); + goto shutdown; + } + + /* + * Key generation + */ + + /* These commands require keygen. */ + if (certutil.commands[cmd_CertReq].activated || + certutil.commands[cmd_CreateAndAddCert].activated || + certutil.commands[cmd_GenKeyPair].activated) { + /* XXX Give it a nickname. */ + privkey = + CERTUTIL_GeneratePrivateKey(keytype, slot, keysize, + publicExponent, + certutil.options[opt_NoiseFile].arg, + &pubkey, + certutil.options[opt_PQGFile].arg, + &pwdata); + if (privkey == NULL) { + SECU_PrintError(progName, "unable to generate key(s)\n"); + rv = SECFailure; + goto shutdown; + } + privkey->wincx = &pwdata; + PORT_Assert(pubkey != NULL); + + /* If all that was needed was keygen, exit. */ + if (certutil.commands[cmd_GenKeyPair].activated) { + rv = SECSuccess; + goto shutdown; + } + } + + /* + * Certificate request + */ + + /* Make a cert request (-R or -S). */ + if (certutil.commands[cmd_CreateAndAddCert].activated || + certutil.commands[cmd_CertReq].activated) { + rv = CertReq(privkey, pubkey, keytype, hashAlgTag, subject, + certutil.options[opt_PhoneNumber].arg, + certutil.options[opt_ASCIIForIO].activated, + certutil.options[opt_ExtendedEmailAddrs].arg, + certutil.options[opt_ExtendedDNSNames].arg, + outFile ? outFile : PR_STDOUT); + if (rv) + goto shutdown; + privkey->wincx = &pwdata; + } + + /* + * Certificate creation + */ + + /* If making and adding a cert, load the cert request file + * and output the cert to another file. + */ + if (certutil.commands[cmd_CreateAndAddCert].activated) { + PR_Close(outFile); + inFile = PR_Open(certreqfile, PR_RDONLY, 0); + if (!inFile) { + PR_fprintf(PR_STDERR, "Failed to open file \"%s\" (%ld, %ld).\n", + certreqfile, PR_GetError(), PR_GetOSError()); + rv = SECFailure; + goto shutdown; + } + outFile = PR_Open(certfile, PR_RDWR | PR_CREATE_FILE, 00660); + if (!outFile) { + PR_fprintf(PR_STDERR, "Failed to open file \"%s\" (%ld, %ld).\n", + certfile, PR_GetError(), PR_GetOSError()); + rv = SECFailure; + goto shutdown; + } + } + + /* Create a certificate (-C or -S). */ + if (certutil.commands[cmd_CreateAndAddCert].activated || + certutil.commands[cmd_CreateNewCert].activated) { + rv = CreateCert(certHandle, + certutil.options[opt_IssuerName].arg, + inFile, outFile, privkey, &pwdata, hashAlgTag, + serialNumber, warpmonths, validitylength, + certutil.options[opt_ExtendedEmailAddrs].arg, + certutil.options[opt_ExtendedDNSNames].arg, + certutil.options[opt_ASCIIForIO].activated, + certutil.options[opt_SelfSign].activated, + certutil.options[opt_AddKeyUsageExt].activated, + certutil.options[opt_AddExtKeyUsageExt].activated, + certutil.options[opt_AddBasicConstraintExt].activated, + certutil.options[opt_AddAuthorityKeyIDExt].activated, + certutil.options[opt_AddCRLDistPtsExt].activated, + certutil.options[opt_AddNSCertTypeExt].activated); + if (rv) + goto shutdown; + } + + /* + * Adding a cert to the database (or slot) + */ + + if (certutil.commands[cmd_CreateAndAddCert].activated) { + PORT_Assert(inFile != PR_STDIN); + PR_Close(inFile); + PR_Close(outFile); + inFile = PR_Open(certfile, PR_RDONLY, 0); + if (!inFile) { + PR_fprintf(PR_STDERR, "Failed to open file \"%s\" (%ld, %ld).\n", + certfile, PR_GetError(), PR_GetOSError()); + rv = SECFailure; + goto shutdown; + } + } + + if (certutil.commands[cmd_CreateAndAddCert].activated || + certutil.commands[cmd_AddCert].activated || + certutil.commands[cmd_AddEmailCert].activated) { + rv = AddCert(slot, certHandle, name, + certutil.options[opt_Trust].arg, + inFile, + certutil.options[opt_ASCIIForIO].activated, + certutil.commands[cmd_AddEmailCert].activated,&pwdata); + if (rv) + goto shutdown; + } + + if (certutil.commands[cmd_CreateAndAddCert].activated) { + PORT_Assert(inFile != PR_STDIN); + PR_Close(inFile); + PR_Delete(certfile); + PR_Delete(certreqfile); + } + +shutdown: + if (slot) { + PK11_FreeSlot(slot); + } + if (privkey) { + SECKEY_DestroyPrivateKey(privkey); + } + if (pubkey) { + SECKEY_DestroyPublicKey(pubkey); + } + + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + + if (rv == SECSuccess) { + return 0; + } else { + return 255; + } +} diff --git a/security/nss/cmd/certutil/keystuff.c b/security/nss/cmd/certutil/keystuff.c new file mode 100644 index 000000000..317443a27 --- /dev/null +++ b/security/nss/cmd/certutil/keystuff.c @@ -0,0 +1,411 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "secutil.h" + +#if defined(XP_UNIX) +#include <unistd.h> +#include <sys/time.h> +#include <termios.h> +#endif + +#if defined(XP_WIN) || defined (XP_PC) +#include <time.h> +#include <conio.h> +#endif + +#if defined(__sun) && !defined(SVR4) +extern int fclose(FILE*); +extern int fprintf(FILE *, char *, ...); +extern int isatty(int); +extern char *sys_errlist[]; +#define strerror(errno) sys_errlist[errno] +#endif + +#include "nspr.h" +#include "prtypes.h" +#include "prtime.h" +#include "prlong.h" + +#include "pk11func.h" +#include "secrng.h" +#include "pqgutil.h" + +#define NUM_KEYSTROKES 120 +#define RAND_BUF_SIZE 60 + +#define ERROR_BREAK rv = SECFailure;break; + +const SEC_ASN1Template SECKEY_PQGParamsTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPQGParams) }, + { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,prime) }, + { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,subPrime) }, + { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,base) }, + { 0, } +}; + +/* returns 0 for success, -1 for failure (EOF encountered) */ +static int +UpdateRNG(void) +{ + char * randbuf; + int fd, i, count; + int c; + int rv = 0; +#ifdef XP_UNIX + cc_t orig_cc_min; + cc_t orig_cc_time; + tcflag_t orig_lflag; + struct termios tio; +#endif + +#define FPS fprintf(stderr, + FPS "\n"); + FPS "A random seed must be generated that will be used in the\n"); + FPS "creation of your key. One of the easiest ways to create a\n"); + FPS "random seed is to use the timing of keystrokes on a keyboard.\n"); + FPS "\n"); + FPS "To begin, type keys on the keyboard until this progress meter\n"); + FPS "is full. DO NOT USE THE AUTOREPEAT FUNCTION ON YOUR KEYBOARD!\n"); + FPS "\n"); + FPS "\n"); + FPS "Continue typing until the progress meter is full:\n\n"); + FPS "| |\r"); + + /* turn off echo on stdin & return on 1 char instead of NL */ + fd = fileno(stdin); + +#if defined(XP_UNIX) && !defined(VMS) + tcgetattr(fd, &tio); + orig_lflag = tio.c_lflag; + orig_cc_min = tio.c_cc[VMIN]; + orig_cc_time = tio.c_cc[VTIME]; + tio.c_lflag &= ~ECHO; + tio.c_lflag &= ~ICANON; + tio.c_cc[VMIN] = 1; + tio.c_cc[VTIME] = 0; + tcsetattr(fd, TCSAFLUSH, &tio); +#endif + + /* Get random noise from keyboard strokes */ + randbuf = (char *) PORT_Alloc(RAND_BUF_SIZE); + count = 0; + while (count < NUM_KEYSTROKES+1) { +#ifdef VMS + c = GENERIC_GETCHAR_NOECHO(); +#elif XP_UNIX + c = getc(stdin); +#else + c = getch(); +#endif + if (c == EOF) { + rv = -1; + break; + } + PK11_RandomUpdate(randbuf, sizeof(randbuf)); + if (c != randbuf[0]) { + randbuf[0] = c; + FPS "\r|"); + for (i=0; i<count/(NUM_KEYSTROKES/RAND_BUF_SIZE); i++) { + FPS "*"); + } + if (count%(NUM_KEYSTROKES/RAND_BUF_SIZE) == 1) + FPS "/"); + count++; + } + } + free(randbuf); + + FPS "\n\n"); + FPS "Finished. Press enter to continue: "); +#if defined(VMS) + while((c = GENERIC_GETCHAR_NO_ECHO()) != '\r' && c != EOF) + ; +#else + while ((c = getc(stdin)) != '\n' && c != EOF) + ; +#endif + if (c == EOF) + rv = -1; + FPS "\n"); + +#undef FPS + +#if defined(XP_UNIX) && !defined(VMS) + /* set back termio the way it was */ + tio.c_lflag = orig_lflag; + tio.c_cc[VMIN] = orig_cc_min; + tio.c_cc[VTIME] = orig_cc_time; + tcsetattr(fd, TCSAFLUSH, &tio); +#endif + return rv; +} + + +static unsigned char P[] = { 0x00, 0x8d, 0xf2, 0xa4, 0x94, 0x49, 0x22, 0x76, + 0xaa, 0x3d, 0x25, 0x75, 0x9b, 0xb0, 0x68, 0x69, + 0xcb, 0xea, 0xc0, 0xd8, 0x3a, 0xfb, 0x8d, 0x0c, + 0xf7, 0xcb, 0xb8, 0x32, 0x4f, 0x0d, 0x78, 0x82, + 0xe5, 0xd0, 0x76, 0x2f, 0xc5, 0xb7, 0x21, 0x0e, + 0xaf, 0xc2, 0xe9, 0xad, 0xac, 0x32, 0xab, 0x7a, + 0xac, 0x49, 0x69, 0x3d, 0xfb, 0xf8, 0x37, 0x24, + 0xc2, 0xec, 0x07, 0x36, 0xee, 0x31, 0xc8, 0x02, + 0x91 }; +static unsigned char Q[] = { 0x00, 0xc7, 0x73, 0x21, 0x8c, 0x73, 0x7e, 0xc8, + 0xee, 0x99, 0x3b, 0x4f, 0x2d, 0xed, 0x30, 0xf4, + 0x8e, 0xda, 0xce, 0x91, 0x5f }; +static unsigned char G[] = { 0x00, 0x62, 0x6d, 0x02, 0x78, 0x39, 0xea, 0x0a, + 0x13, 0x41, 0x31, 0x63, 0xa5, 0x5b, 0x4c, 0xb5, + 0x00, 0x29, 0x9d, 0x55, 0x22, 0x95, 0x6c, 0xef, + 0xcb, 0x3b, 0xff, 0x10, 0xf3, 0x99, 0xce, 0x2c, + 0x2e, 0x71, 0xcb, 0x9d, 0xe5, 0xfa, 0x24, 0xba, + 0xbf, 0x58, 0xe5, 0xb7, 0x95, 0x21, 0x92, 0x5c, + 0x9c, 0xc4, 0x2e, 0x9f, 0x6f, 0x46, 0x4b, 0x08, + 0x8c, 0xc5, 0x72, 0xaf, 0x53, 0xe6, 0xd7, 0x88, + 0x02 }; + +static SECKEYPQGParams default_pqg_params = { + NULL, + { 0, P, sizeof(P) }, + { 0, Q, sizeof(Q) }, + { 0, G, sizeof(G) } +}; + +static SECKEYPQGParams * +decode_pqg_params(char *str) +{ + char *buf; + unsigned int len; + PRArenaPool *arena; + SECKEYPQGParams *params; + SECStatus status; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) + return NULL; + + params = PORT_ArenaZAlloc(arena, sizeof(SECKEYPQGParams)); + if (params == NULL) + goto loser; + params->arena = arena; + + buf = (char *)ATOB_AsciiToData(str, &len); + if ((buf == NULL) || (len == 0)) + goto loser; + + status = SEC_ASN1Decode(arena, params, SECKEY_PQGParamsTemplate, buf, len); + if (status != SECSuccess) + goto loser; + + return params; + +loser: + if (arena != NULL) + PORT_FreeArena(arena, PR_FALSE); + return NULL; +} + +void +CERTUTIL_DestroyParamsPQG(SECKEYPQGParams *params) +{ + if (params->arena) { + PORT_FreeArena(params->arena, PR_FALSE); + } +} + +static int +pqg_prime_bits(char *str) +{ + SECKEYPQGParams *params = NULL; + int primeBits = 0, i; + + params = decode_pqg_params(str); + if (params == NULL) + goto done; /* lose */ + + for (i = 0; params->prime.data[i] == 0; i++) + /* empty */; + primeBits = (params->prime.len - i) * 8; + +done: + if (params != NULL) + CERTUTIL_DestroyParamsPQG(params); + return primeBits; +} + +static char * +SECU_GetpqgString(char *filename) +{ + char phrase[400]; + FILE *fh; + char *rv; + + fh = fopen(filename,"r"); + rv = fgets (phrase, sizeof(phrase), fh); + + fclose(fh); + if (phrase[strlen(phrase)-1] == '\n') + phrase[strlen(phrase)-1] = '\0'; + if (rv) { + return (char*) PORT_Strdup(phrase); + } + fprintf(stderr,"pqg file contain no data\n"); + return NULL; +} + +SECKEYPQGParams* +getpqgfromfile(int keyBits, char *pqgFile) +{ + char *end, *str, *pqgString; + int primeBits; + + pqgString = SECU_GetpqgString(pqgFile); + if (pqgString) + str = PORT_Strdup(pqgString); + else + return NULL; + + do { + end = PORT_Strchr(str, ','); + if (end) + *end = '\0'; + primeBits = pqg_prime_bits(str); + if (keyBits == primeBits) + goto found_match; + str = end + 1; + } while (end); + + PORT_Free(pqgString); + PORT_Free(str); + return NULL; + +found_match: + PORT_Free(pqgString); + PORT_Free(str); + return decode_pqg_params(str); +} + +void CERTUTIL_FileForRNG(char *noise) +{ + char buf[2048]; + PRFileDesc *fd; + PRInt32 count; + + fd = PR_OpenFile(noise,PR_RDONLY,0666); + if (!fd) return; + + do { + count = PR_Read(fd,buf,sizeof(buf)); + if (count > 0) { + PK11_RandomUpdate(buf,count); + } + } while (count > 0); + + PR_Close(fd); + +} + +SECKEYPrivateKey * +CERTUTIL_GeneratePrivateKey(KeyType keytype, PK11SlotInfo *slot, int size, + int publicExponent, char *noise, + SECKEYPublicKey **pubkeyp, char *pqgFile, + secuPWData *pwdata) +{ + CK_MECHANISM_TYPE mechanism; + SECOidTag algtag; + PK11RSAGenParams rsaparams; + SECKEYPQGParams *dsaparams = NULL; + void *params; + PRArenaPool *dsaparena; + + /* + * Do some random-number initialization. + */ + + if (noise) { + CERTUTIL_FileForRNG(noise); + } else { + int rv = UpdateRNG(); + if (rv) { + PORT_SetError(PR_END_OF_FILE_ERROR); + return NULL; + } + } + + switch (keytype) { + case rsaKey: + rsaparams.keySizeInBits = size; + rsaparams.pe = publicExponent; + mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; + algtag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; + params = &rsaparams; + break; + case dsaKey: + mechanism = CKM_DSA_KEY_PAIR_GEN; + algtag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; + if (pqgFile) { + dsaparams = getpqgfromfile(size, pqgFile); + } else { + dsaparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (dsaparena == NULL) return NULL; + dsaparams = PORT_ArenaZAlloc(dsaparena, sizeof(SECKEYPQGParams)); + if (dsaparams == NULL) return NULL; + dsaparams->arena = dsaparena; + SECITEM_AllocItem(dsaparena, &dsaparams->prime, sizeof P); + SECITEM_AllocItem(dsaparena, &dsaparams->subPrime, sizeof Q); + SECITEM_AllocItem(dsaparena, &dsaparams->base, sizeof G); + PORT_Memcpy(dsaparams->prime.data, P, dsaparams->prime.len); + PORT_Memcpy(dsaparams->subPrime.data, Q, dsaparams->subPrime.len); + PORT_Memcpy(dsaparams->base.data, G, dsaparams->base.len); + } + params = dsaparams; + break; + default: + return NULL; + } + + if (slot == NULL) + return NULL; + + if (PK11_Authenticate(slot, PR_TRUE, pwdata) != SECSuccess) + return NULL; + + fprintf(stderr, "\n\n"); + fprintf(stderr, "Generating key. This may take a few moments...\n\n"); + + return PK11_GenerateKeyPair(slot, mechanism, params, pubkeyp, + PR_TRUE /*isPerm*/, PR_TRUE /*isSensitive*/, + pwdata /*wincx*/); +} diff --git a/security/nss/cmd/certutil/makefile.win b/security/nss/cmd/certutil/makefile.win new file mode 100644 index 000000000..26cdc0651 --- /dev/null +++ b/security/nss/cmd/certutil/makefile.win @@ -0,0 +1,155 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +VERBOSE = 1 +include <manifest.mn> + +PROGRAM = certutil +PROGRAM = $(OBJDIR)\$(PROGRAM).exe + +include <$(DEPTH)\config\config.mak> + + +# let manifest generate C_OBJS, it will prepend ./$(OBJDIR)/ +# rules.mak will append C_OBJS onto OBJS. +# OBJS = $(CSRCS:.c=.obj) + +# include files are looked for in $LINCS and $INCS. +# $LINCS is in manifest.mnw, computed from REQUIRES= +INCS = $(INCS) \ + -I$(DEPTH)/security/lib/cert \ + -I../include \ + $(NULL) + +IGNORE_ME = \ + -I$(DEPTH)/security/lib/key \ + -I$(DEPTH)/security/lib/util \ + + +WINFE = $(DEPTH)/cmd/winfe/mkfiles$(MOZ_BITS)/x86Dbg + +# these files are the content of libdbm +DBM_LIB = \ + $(WINFE)/DB.obj \ + $(WINFE)/HASH.obj \ + $(WINFE)/H_BIGKEY.obj \ + $(WINFE)/H_PAGE.obj \ + $(WINFE)/H_LOG2.obj \ + $(WINFE)/H_FUNC.obj \ + $(WINFE)/HASH_BUF.obj \ + $(NULL) + +MOZ_LIBS = \ + $(WINFE)/ALLXPSTR.obj \ + $(WINFE)/XP_ERROR.obj \ + $(WINFE)/XPASSERT.obj \ + $(WINFE)/XP_REG.obj \ + $(WINFE)/XP_TRACE.obj \ + $(DBM_LIB) \ + $(WINFE)/XP_STR.obj \ + $(WINFE)/MKTEMP.obj \ + $(NULL) + +SEC_LIBS = \ + $(DIST)/lib/cert$(MOZ_BITS).lib \ + $(DIST)/lib/crypto$(MOZ_BITS).lib \ + $(DIST)/lib/hash$(MOZ_BITS).lib \ + $(DIST)/lib/key$(MOZ_BITS).lib \ + $(DIST)/lib/pkcs7$(MOZ_BITS).lib \ + $(DIST)/lib/secmod$(MOZ_BITS).lib \ + $(DIST)/lib/secutl$(MOZ_BITS).lib \ + $(DIST)/lib/ssl$(MOZ_BITS).lib \ + $(NULL) + +LLFLAGS = $(LLFLAGS) \ + ../lib/$(OBJDIR)/sectool$(MOZ_BITS).lib \ + $(SEC_LIBS) \ + $(MOZ_LIBS) \ + $(DEPTH)/nspr/src/$(OBJDIR)/getopt.obj \ + $(LIBNSPR) \ + $(NULL) + + +# awt3240.lib # brpref32.lib # cert32.lib +# crypto32.lib # dllcom.lib # editor32.lib +# edpref32.lib # edtplug.lib # font.lib +# hash32.lib # htmldg32.lib # img32.lib +# javart32.lib # jbn3240.lib # jdb3240.lib +# jmc.lib # jpeg3240.lib # jpw3240.lib +# jrt3240.lib # js3240.lib # jsd3240.lib +# key32.lib # libapplet32.lib # libnjs32.lib +# libnsc32.lib # libreg32.lib # mm3240.lib +# mnpref32.lib # netcst32.lib # nsdlg32.lib +# nsldap32.lib # nsldaps32.lib # nsn32.lib +# pkcs1232.lib # pkcs732.lib # pr3240.lib +# prefui32.lib # prefuuid.lib # secmod32.lib +# secnav32.lib # secutl32.lib # softup32.lib +# sp3240.lib # ssl32.lib # uni3200.lib +# unicvt32.lib # win32md.lib # winfont.lib +# xppref32.lib # zlib32.lib + +include <$(DEPTH)\config\rules.mak> + + +INSTALL = $(MAKE_INSTALL) + +objs: $(OBJS) + +$(PROGRAM):: + $(INSTALL) $(DIST)/bin/pr3240.dll ./$(OBJDIR) + +programs: $(PROGRAM) + +install:: $(TARGETS) + $(INSTALL) $(TARGETS) $(DIST)/bin + +# ALLXPSTR.obj XP_ALLOC.obj XP_HASH.obj XP_RGB.obj XP_WRAP.obj +# CXPRINT.obj XP_C.cl XP_LIST.obj XP_SEC.obj netscape.exp +# CXPRNDLG.obj XP_CNTXT.obj XP_MD5.obj XP_STR.obj xp.pch +# EXPORT.obj XP_CORE.obj XP_MESG.obj XP_THRMO.obj xppref32.dll +# XPASSERT.obj XP_ERROR.obj XP_RECT.obj XP_TIME.obj +# XPLOCALE.obj XP_FILE.obj XP_REG.obj XP_TRACE.obj + +symbols: + @echo "CSRCS = $(CSRCS)" + @echo "INCS = $(INCS)" + @echo "OBJS = $(OBJS)" + @echo "LIBRARY = $(LIBRARY)" + @echo "PROGRAM = $(PROGRAM)" + @echo "TARGETS = $(TARGETS)" + @echo "DIST = $(DIST)" + @echo "VERSION_NUMBER = $(VERSION_NUMBER)" + @echo "WINFE = $(WINFE)" + @echo "DBM_LIB = $(DBM_LIB)" + @echo "INSTALL = $(INSTALL)" + diff --git a/security/nss/cmd/certutil/manifest.mn b/security/nss/cmd/certutil/manifest.mn new file mode 100644 index 000000000..9bf7af5b8 --- /dev/null +++ b/security/nss/cmd/certutil/manifest.mn @@ -0,0 +1,52 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +DEFINES += -DNSPR20 + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +CSRCS = \ + certutil.c \ + keystuff.c \ + $(NULL) + +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = dbm seccmd + +PROGRAM = certutil + +#USE_STATIC_LIBS = 1 diff --git a/security/nss/cmd/checkcert/Makefile b/security/nss/cmd/checkcert/Makefile new file mode 100644 index 000000000..573c12cac --- /dev/null +++ b/security/nss/cmd/checkcert/Makefile @@ -0,0 +1,76 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + + +include ../platrules.mk + diff --git a/security/nss/cmd/checkcert/checkcert.c b/security/nss/cmd/checkcert/checkcert.c new file mode 100644 index 000000000..0cd5e61aa --- /dev/null +++ b/security/nss/cmd/checkcert/checkcert.c @@ -0,0 +1,640 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "secutil.h" +#include "plgetopt.h" +#include "cert.h" +#include "secoid.h" +#include "cryptohi.h" + +/* maximum supported modulus length in bits (indicate problem if over this) */ +#define MAX_MODULUS (1024) + + +static void Usage(char *progName) +{ + fprintf(stderr, "Usage: %s [aAvf] [certtocheck] [issuingcert]\n", + progName); + fprintf(stderr, "%-20s Cert to check is base64 encoded\n", + "-a"); + fprintf(stderr, "%-20s Issuer's cert is base64 encoded\n", + "-A"); + fprintf(stderr, "%-20s Verbose (indicate decoding progress etc.)\n", + "-v"); + fprintf(stderr, "%-20s Force sanity checks even if pretty print fails.\n", + "-f"); + fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n", + "-o output"); + fprintf(stderr, "%-20s Specify the input type (no default)\n", + "-t type"); + exit(-1); +} + + +/* + * Check integer field named fieldName, printing out results and + * returning the length of the integer in bits + */ + +static +int checkInteger(SECItem *intItem, char *fieldName, int verbose) +{ + int len, bitlen; + if (verbose) { + printf("Checking %s\n", fieldName); + } + + len = intItem->len; + + if (len && (intItem->data[0] & 0x80)) { + printf("PROBLEM: %s is NEGATIVE 2's-complement integer.\n", + fieldName); + } + + + /* calculate bit length and check for unnecessary leading zeros */ + bitlen = len << 3; + if (len > 1 && intItem->data[0] == 0) { + /* leading zero byte(s) */ + if (!(intItem->data[1] & 0x80)) { + printf("PROBLEM: %s has unneeded leading zeros. Violates DER.\n", + fieldName); + } + /* strip leading zeros in length calculation */ + { + int i=0; + while (bitlen > 8 && intItem->data[i] == 0) { + bitlen -= 8; + i++; + } + } + } + return bitlen; +} + + + + +static +void checkName(CERTName *n, char *fieldName, int verbose) +{ + char *v=0; + if (verbose) { + printf("Checking %s\n", fieldName); + } + + v = CERT_GetCountryName(n); + if (!v) { + printf("PROBLEM: %s lacks Country Name (C)\n", + fieldName); + } + PORT_Free(v); + + v = CERT_GetOrgName(n); + if (!v) { + printf("PROBLEM: %s lacks Organization Name (O)\n", + fieldName); + } + PORT_Free(v); + + v = CERT_GetOrgUnitName(n); + if (!v) { + printf("WARNING: %s lacks Organization Unit Name (OU)\n", + fieldName); + } + PORT_Free(v); + + v = CERT_GetCommonName(n); + if (!v) { + printf("PROBLEM: %s lacks Common Name (CN)\n", + fieldName); + } + PORT_Free(v); +} + + + + +/* + * Private version of verification that checks for agreement between + * signature algorithm oid (at the SignedData level) and oid in DigestInfo. + * + */ + + +/* Returns the tag for the hash algorithm in the given signature algorithm */ + static + int hashAlg(int sigAlgTag) { + int rv; + switch(sigAlgTag) { + case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: + rv = SEC_OID_MD2; + break; + case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: + rv = SEC_OID_MD5; + break; + case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: + rv = SEC_OID_SHA1; + break; + default: + rv = -1; + } + return rv; + } + + + +struct VFYContextStr { + int alg; + unsigned char digest[32]; + void *hasher; + void (*begin)(void *); + void (*update)(void *, unsigned char*, unsigned); + SECStatus (*end)(void *, unsigned char*, unsigned int*, unsigned); + void (*destroy)(void *, PRBool); +}; + + +static +SECStatus +OurVerifyData(unsigned char *buf, int len, SECKEYPublicKey *key, + SECItem *sig, SECAlgorithmID *sigAlgorithm) +{ + SECStatus rv; + VFYContext *cx; + SECOidData *sigAlgOid, *oiddata; + int sigAlgTag; + int hashAlgTag; + int showDigestOid=0; + + cx = VFY_CreateContext(key, sig, SECOID_GetAlgorithmTag(sigAlgorithm), + NULL); + if (cx == NULL) + return SECFailure; + + sigAlgOid = SECOID_FindOID(&sigAlgorithm->algorithm); + if (sigAlgOid == 0) + return SECFailure; + sigAlgTag = sigAlgOid->offset; + + hashAlgTag = hashAlg(sigAlgTag); + if (hashAlgTag == -1) { + printf("PROBLEM: Unsupported Digest Algorithm in DigestInfo"); + showDigestOid = 1; + } else if (hashAlgTag != cx->alg) { + printf("PROBLEM: Digest OID in DigestInfo is incompatible " + "with Signature Algorithm\n"); + showDigestOid = 1; + } + + if (showDigestOid) { + oiddata = SECOID_FindOIDByTag(cx->alg); + if ( oiddata ) { + printf("PROBLEM: (cont) Digest OID is %s\n", oiddata->desc); + } else { + SECU_PrintAsHex(stdout, + &oiddata->oid, "PROBLEM: UNKNOWN OID", 0); + } + } + + rv = VFY_Begin(cx); + if (rv == SECSuccess) { + rv = VFY_Update(cx, buf, len); + if (rv == SECSuccess) + rv = VFY_End(cx); + } + + VFY_DestroyContext(cx, PR_TRUE); + return rv; +} + + + +static +SECStatus +OurVerifySignedData(CERTSignedData *sd, CERTCertificate *cert) +{ + SECItem sig; + SECKEYPublicKey *pubKey = 0; + SECStatus rv; + + /* check the certificate's validity */ + rv = CERT_CertTimesValid(cert); + if ( rv ) { + return(SECFailure); + } + + /* get cert's public key */ + pubKey = CERT_ExtractPublicKey(cert); + if ( !pubKey ) { + return(SECFailure); + } + + /* check the signature */ + sig = sd->signature; + DER_ConvertBitString(&sig); + rv = OurVerifyData(sd->data.data, sd->data.len, pubKey, &sig, + &sd->signatureAlgorithm); + + SECKEY_DestroyPublicKey(pubKey); + + if ( rv ) { + return(SECFailure); + } + + return(SECSuccess); +} + + + + +static +CERTCertificate *createEmptyCertificate(void) +{ + PRArenaPool *arena = 0; + CERTCertificate *c = 0; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if ( !arena ) { + return 0; + } + + + c = (CERTCertificate *) PORT_ArenaZAlloc(arena, sizeof(CERTCertificate)); + + if (c) { + c->referenceCount = 1; + c->arena = arena; + } else { + PORT_FreeArena(arena,PR_TRUE); + } + + return c; +} + + + + +int main(int argc, char **argv) +{ + int rv, verbose=0, force=0; + int ascii=0, issuerAscii=0; + char *progName=0; + PRFileDesc *inFile=0, *issuerCertFile=0; + SECItem derCert, derIssuerCert; + PRArenaPool *arena=0; + CERTSignedData *signedData=0; + CERTCertificate *cert=0, *issuerCert=0; + SECKEYPublicKey *rsapubkey=0; + SECAlgorithmID md5WithRSAEncryption, md2WithRSAEncryption; + SECAlgorithmID sha1WithRSAEncryption, rsaEncryption; + SECItem spk; + int selfSigned=0; + int invalid=0; + char *inFileName = NULL, *issuerCertFileName = NULL; + PLOptState *optstate; + PLOptStatus status; + + PORT_Memset(&md5WithRSAEncryption, 0, sizeof(md5WithRSAEncryption)); + PORT_Memset(&md2WithRSAEncryption, 0, sizeof(md2WithRSAEncryption)); + PORT_Memset(&sha1WithRSAEncryption, 0, sizeof(sha1WithRSAEncryption)); + PORT_Memset(&rsaEncryption, 0, sizeof(rsaEncryption)); + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + optstate = PL_CreateOptState(argc, argv, "aAvf"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case 'v': + verbose = 1; + break; + + case 'f': + force = 1; + break; + + case 'a': + ascii = 1; + break; + + case 'A': + issuerAscii = 1; + break; + + case '\0': + if (!inFileName) + inFileName = PL_strdup(optstate->value); + else if (!issuerCertFileName) + issuerCertFileName = PL_strdup(optstate->value); + else + Usage(progName); + break; + } + } + + if (!inFileName || !issuerCertFileName || status == PL_OPT_BAD) { + /* insufficient or excess args */ + Usage(progName); + } + + inFile = PR_Open(inFileName, PR_RDONLY, 0); + if (!inFile) { + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", + progName, inFileName); + exit(1); + } + + issuerCertFile = PR_Open(issuerCertFileName, PR_RDONLY, 0); + if (!issuerCertFile) { + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", + progName, issuerCertFileName); + exit(1); + } + + if (SECU_ReadDERFromFile(&derCert, inFile, ascii) != SECSuccess) { + printf("Couldn't read input certificate as DER binary or base64\n"); + exit(1); + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == 0) { + fprintf(stderr,"%s: can't allocate scratch arena!", progName); + exit(1); + } + + if (issuerCertFile) { + CERTSignedData *issuerCertSD=0; + if (SECU_ReadDERFromFile(&derIssuerCert, issuerCertFile, issuerAscii) + != SECSuccess) { + printf("Couldn't read issuer certificate as DER binary or base64.\n"); + exit(1); + } + issuerCertSD = (CERTSignedData *) PORT_ArenaZAlloc(arena, + sizeof(CERTSignedData)); + if (!issuerCertSD) { + fprintf(stderr,"%s: can't allocate issuer signed data!", progName); + exit(1); + } + rv = SEC_ASN1DecodeItem(arena, issuerCertSD, + SEC_ASN1_GET(CERT_SignedDataTemplate), + &derIssuerCert); + if (rv) { + fprintf(stderr, "%s: Issuer cert isn't X509 SIGNED Data?\n", + progName); + exit(1); + } + issuerCert = createEmptyCertificate(); + if (!issuerCert) { + printf("%s: can't allocate space for issuer cert.", progName); + exit(1); + } + rv = SEC_ASN1DecodeItem(arena, issuerCert, + SEC_ASN1_GET(CERT_CertificateTemplate), + &issuerCertSD->data); + if (rv) { + printf("%s: Does not appear to be an X509 Certificate.\n", + progName); + exit(1); + } + } + + signedData = (CERTSignedData *) PORT_ArenaZAlloc(arena,sizeof(CERTSignedData)); + if (!signedData) { + fprintf(stderr,"%s: can't allocate signedData!", progName); + exit(1); + } + + rv = SEC_ASN1DecodeItem(arena, signedData, + SEC_ASN1_GET(CERT_SignedDataTemplate), + &derCert); + if (rv) { + fprintf(stderr, "%s: Does not appear to be X509 SIGNED Data.\n", + progName); + exit(1); + } + + if (verbose) { + printf("Decoded ok as X509 SIGNED data.\n"); + } + + cert = createEmptyCertificate(); + if (!cert) { + fprintf(stderr, "%s: can't allocate cert", progName); + exit(1); + } + + rv = SEC_ASN1DecodeItem(arena, cert, + SEC_ASN1_GET(CERT_CertificateTemplate), + &signedData->data); + if (rv) { + fprintf(stderr, "%s: Does not appear to be an X509 Certificate.\n", + progName); + exit(1); + } + + + if (verbose) { + printf("Decoded ok as an X509 certificate.\n"); + } + + + rv = SECU_PrintSignedData(stdout, &derCert, "Certificate", 0, + SECU_PrintCertificate); + + if (rv) { + fprintf(stderr, "%s: Unable to pretty print cert. Error: %d\n", + progName, PORT_GetError()); + if (!force) { + exit(1); + } + } + + + /* Do various checks on the cert */ + + printf("\n"); + + /* Check algorithms */ + SECOID_SetAlgorithmID(arena, &md5WithRSAEncryption, + SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION, NULL); + + SECOID_SetAlgorithmID(arena, &md2WithRSAEncryption, + SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION, NULL); + + SECOID_SetAlgorithmID(arena, &sha1WithRSAEncryption, + SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION, NULL); + + SECOID_SetAlgorithmID(arena, &rsaEncryption, + SEC_OID_PKCS1_RSA_ENCRYPTION, NULL); + + { + int isMD5RSA = (SECOID_CompareAlgorithmID(&cert->signature, + &md5WithRSAEncryption) == 0); + int isMD2RSA = (SECOID_CompareAlgorithmID(&cert->signature, + &md2WithRSAEncryption) == 0); + int isSHA1RSA = (SECOID_CompareAlgorithmID(&cert->signature, + &sha1WithRSAEncryption) == 0); + + if (verbose) { + printf("\nDoing algorithm checks.\n"); + } + + if (!(isMD5RSA || isMD2RSA || isSHA1RSA)) { + printf("PROBLEM: Signature not PKCS1 MD5, MD2, or SHA1 + RSA.\n"); + } else if (!isMD5RSA) { + printf("WARNING: Signature not PKCS1 MD5 with RSA Encryption\n"); + } + + if (SECOID_CompareAlgorithmID(&cert->signature, + &signedData->signatureAlgorithm)) { + printf("PROBLEM: Algorithm in sig and certInfo don't match.\n"); + } + } + + if (SECOID_CompareAlgorithmID(&cert->subjectPublicKeyInfo.algorithm, + &rsaEncryption)) { + printf("PROBLEM: Public key algorithm is not PKCS1 RSA Encryption.\n"); + } + + /* Check further public key properties */ + spk = cert->subjectPublicKeyInfo.subjectPublicKey; + DER_ConvertBitString(&spk); + + if (verbose) { + printf("\nsubjectPublicKey DER\n"); + rv = DER_PrettyPrint(stdout, &spk, PR_FALSE); + printf("\n"); + } + + rsapubkey = (SECKEYPublicKey *) + PORT_ArenaZAlloc(arena,sizeof(SECKEYPublicKey)); + if (!rsapubkey) { + fprintf(stderr, "%s: rsapubkey allocation failed.\n", progName); + exit(1); + } + + rv = SEC_ASN1DecodeItem(arena, rsapubkey, + SEC_ASN1_GET(SECKEY_RSAPublicKeyTemplate), &spk); + if (rv) { + printf("PROBLEM: subjectPublicKey is not a DER PKCS1 RSAPublicKey.\n"); + } else { + int mlen; + int pubexp; + if (verbose) { + printf("Decoded RSA Public Key ok. Doing key checks.\n"); + } + PORT_Assert(rsapubkey->keyType == rsaKey); /* XXX RSA */ + mlen = checkInteger(&rsapubkey->u.rsa.modulus, "Modulus", verbose); + printf("INFO: Public Key modulus length in bits: %d\n", mlen); + if (mlen > MAX_MODULUS) { + printf("PROBLEM: Modulus length exceeds %d bits.\n", + MAX_MODULUS); + } + if (mlen < 512) { + printf("WARNING: Short modulus.\n"); + } + if (mlen != (1 << (ffs(mlen)-1))) { + printf("WARNING: Unusual modulus length (not a power of two).\n"); + } + checkInteger(&rsapubkey->u.rsa.publicExponent, "Public Exponent", + verbose); + pubexp = DER_GetInteger(&rsapubkey->u.rsa.publicExponent); + if (pubexp != 17 && pubexp != 3 && pubexp != 65537) { + printf("WARNING: Public exponent not any of: 3, 17, 65537\n"); + } + } + + + /* Name checks */ + checkName(&cert->issuer, "Issuer Name", verbose); + checkName(&cert->subject, "Subject Name", verbose); + + if (issuerCert) { + SECComparison c = + CERT_CompareName(&cert->issuer, &issuerCert->subject); + if (c) { + printf("PROBLEM: Issuer Name and Subject in Issuing Cert differ\n"); + } + } + + /* Check if self-signed */ + selfSigned = (CERT_CompareName(&cert->issuer, &cert->subject) == 0); + if (selfSigned) { + printf("INFO: Certificate is self signed.\n"); + } else { + printf("INFO: Certificate is NOT self-signed.\n"); + } + + + /* Validity time check */ + if (CERT_CertTimesValid(cert) == SECSuccess) { + printf("INFO: Inside validity period of certificate.\n"); + } else { + printf("PROBLEM: Not in validity period of certificate.\n"); + invalid = 1; + } + + /* Signature check if self-signed */ + if (selfSigned && !invalid) { + if (rsapubkey->u.rsa.modulus.len) { + SECStatus ver; + if (verbose) { + printf("Checking self signature.\n"); + } + ver = OurVerifySignedData(signedData, cert); + if (ver != SECSuccess) { + printf("PROBLEM: Verification of self-signature failed!\n"); + } else { + printf("INFO: Self-signature verifies ok.\n"); + } + } else { + printf("INFO: Not checking signature due to key problems.\n"); + } + } else if (!selfSigned && !invalid && issuerCert) { + SECStatus ver; + ver = OurVerifySignedData(signedData, issuerCert); + if (ver != SECSuccess) { + printf("PROBLEM: Verification of issuer's signature failed!\n"); + } else { + printf("INFO: Issuer's signature verifies ok.\n"); + } + } else { + printf("INFO: Not checking signature.\n"); + } + + return 0; +} + + + diff --git a/security/nss/cmd/checkcert/makefile.win b/security/nss/cmd/checkcert/makefile.win new file mode 100644 index 000000000..ff1fe62a7 --- /dev/null +++ b/security/nss/cmd/checkcert/makefile.win @@ -0,0 +1,130 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +VERBOSE = 1 +include <manifest.mn> + +#cannot define PROGRAM in manifest compatibly with NT and UNIX +PROGRAM = checkcert +PROGRAM = ./$(OBJDIR)/$(PROGRAM).exe +include <$(DEPTH)\config\config.mak> + +# let manifest generate C_OBJS, it will prepend ./$(OBJDIR)/ +# rules.mak will append C_OBJS onto OBJS. +# OBJS = $(CSRCS:.c=.obj) + +# include files are looked for in $LINCS and $INCS. +# $LINCS is in manifest.mnw, computed from REQUIRES= +INCS = $(INCS) \ + -I$(DEPTH)/security/lib/cert \ + -I../include \ + $(NULL) + +IGNORE_ME = \ + -I$(DEPTH)/security/lib/key \ + -I$(DEPTH)/security/lib/util \ + $(NULL) + + +WINFE = $(DEPTH)/cmd/winfe/mkfiles$(MOZ_BITS)/x86Dbg + +# these files are the content of libdbm +DBM_LIB = \ + $(WINFE)/DB.obj \ + $(WINFE)/HASH.obj \ + $(WINFE)/H_BIGKEY.obj \ + $(WINFE)/H_PAGE.obj \ + $(WINFE)/H_LOG2.obj \ + $(WINFE)/H_FUNC.obj \ + $(WINFE)/HASH_BUF.obj \ + $(NULL) + +MOZ_LIBS = \ + $(WINFE)/ALLXPSTR.obj \ + $(WINFE)/XP_ERROR.obj \ + $(WINFE)/XPASSERT.obj \ + $(WINFE)/XP_REG.obj \ + $(WINFE)/XP_TRACE.obj \ + $(DBM_LIB) \ + $(WINFE)/XP_STR.obj \ + $(WINFE)/MKTEMP.obj \ + $(NULL) + +SEC_LIBS = \ + $(DIST)/lib/cert$(MOZ_BITS).lib \ + $(DIST)/lib/crypto$(MOZ_BITS).lib \ + $(DIST)/lib/hash$(MOZ_BITS).lib \ + $(DIST)/lib/key$(MOZ_BITS).lib \ + $(DIST)/lib/pkcs7$(MOZ_BITS).lib \ + $(DIST)/lib/secmod$(MOZ_BITS).lib \ + $(DIST)/lib/secutl$(MOZ_BITS).lib \ + $(DIST)/lib/ssl$(MOZ_BITS).lib \ + $(NULL) + +LLFLAGS = $(LLFLAGS) \ + ../lib/$(OBJDIR)/sectool$(MOZ_BITS).lib \ + $(SEC_LIBS) \ + $(MOZ_LIBS) \ + $(DEPTH)/nspr/src/$(OBJDIR)/getopt.obj \ + $(LIBNSPR) \ + $(NULL) + + +include <$(DEPTH)\config\rules.mak> + +INSTALL = $(MAKE_INSTALL) + +objs: $(OBJS) + +$(PROGRAM):: + $(INSTALL) $(DIST)/bin/pr3240.dll ./$(OBJDIR) + +programs: $(PROGRAM) + +install:: $(TARGETS) + $(INSTALL) $(TARGETS) $(DIST)/bin + + +symbols: + @echo "CSRCS = $(CSRCS)" + @echo "INCS = $(INCS)" + @echo "OBJS = $(OBJS)" + @echo "LIBRARY = $(LIBRARY)" + @echo "PROGRAM = $(PROGRAM)" + @echo "TARGETS = $(TARGETS)" + @echo "DIST = $(DIST)" + @echo "VERSION_NUMBER = $(VERSION_NUMBER)" + @echo "WINFE = $(WINFE)" + @echo "DBM_LIB = $(DBM_LIB)" + @echo "INSTALL = $(INSTALL)" + diff --git a/security/nss/cmd/checkcert/manifest.mn b/security/nss/cmd/checkcert/manifest.mn new file mode 100644 index 000000000..470c203ec --- /dev/null +++ b/security/nss/cmd/checkcert/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +# This next line is used by .mk files +# and gets translated into $LINCS in manifest.mnw +REQUIRES = seccmd dbm + +DEFINES = -DNSPR20 + +CSRCS = checkcert.c + +PROGRAM = checkcert diff --git a/security/nss/cmd/cmdlib/Makefile b/security/nss/cmd/cmdlib/Makefile new file mode 100644 index 000000000..0769c80a3 --- /dev/null +++ b/security/nss/cmd/cmdlib/Makefile @@ -0,0 +1,75 @@ +#! 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/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). # +####################################################################### + + diff --git a/security/nss/cmd/cmdlib/cmdline.c b/security/nss/cmd/cmdlib/cmdline.c new file mode 100644 index 000000000..84ad35be3 --- /dev/null +++ b/security/nss/cmd/cmdlib/cmdline.c @@ -0,0 +1,474 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 <string.h> +#include <ctype.h> + +#include "cmdutil.h" + +static int s_indent_size = 4; + +void +CMD_SetIndentSize(int size) +{ + s_indent_size = size; +} + +#if 0 +static void +indent(PRFileDesc *out, int level) +{ + int i, j; + for (i=0; i<level; i++) + for (j=0; j<s_indent_size; j++) + PR_fprintf(out, " "); +} +#endif + +struct cmdPrintStateStr { + PRFileDesc *file; + int width; + int indent; + int linepos; +}; + +static void +init_print_ps(cmdPrintState *ps, PRFileDesc *outfile, int width, int indent) +{ + ps->file = (outfile) ? outfile : PR_STDOUT; + ps->width = (width > 0) ? width : 80; + ps->indent = (indent > 0) ? indent : 0; + ps->linepos = 0; +} + +static void +print_ps_indent(cmdPrintState *ps) +{ + int j; + if (ps->linepos != 0) { + PR_fprintf(ps->file, "\n"); + ps->linepos = 0; + } + for (j=0; j<=ps->indent; j++) PR_fprintf(ps->file, " "); + ps->linepos = ps->indent; +} + +static void +print_ps_to_indent(cmdPrintState *ps) +{ + if (ps->linepos > ps->indent) + PR_fprintf(ps->file, "\n"); + while (ps->linepos <= ps->indent) { + PR_fprintf(ps->file, " "); + ps->linepos++; + } +} + +static void +nprintbuf(cmdPrintState *ps, char *buf, int start, int len) +{ + int j; + for (j=start; j<start + len; j++) { + if (buf[j] == '\n') { + PR_fprintf(ps->file, "\n"); + ps->linepos = 0; + print_ps_indent(ps); + } else { + PR_fprintf(ps->file, "%c", buf[j]); + ps->linepos++; + } + } +} + +static void +nprintf(cmdPrintState *ps, char *msg, ...) +{ + char buf[256]; + int i, len, grouplen; + PRBool openquote, openbracket, openparen, openangle, itsaword; + va_list args; + va_start(args, msg); + vsprintf(buf, msg, args); + len = strlen(buf); + /* print_ps_indent(ps); */ + if (len < ps->width - ps->linepos) { + nprintbuf(ps, buf, 0, len + 1); + return; + } + /* group in this order: " [ ( < word > ) ] " */ + i=0; + openquote=openbracket=openparen=openangle=itsaword=PR_FALSE; + while (i<len) { + grouplen = 0; + if (buf[i] == '\"') { openquote = PR_TRUE; grouplen = 1; } + else if (buf[i] == '[') { openbracket = PR_TRUE; grouplen = 1; } + else if (buf[i] == '(') { openparen = PR_TRUE; grouplen = 1; } + else if (buf[i] == '<') { openangle = PR_TRUE; grouplen = 1; } + else itsaword = PR_TRUE; + while (grouplen < len && buf[i+grouplen] != '\0' && + ((openquote && buf[i+grouplen] != '\"') || + (openbracket && buf[i+grouplen] != ']') || + (openparen && buf[i+grouplen] != ')') || + (openangle && buf[i+grouplen] != '>') || + (itsaword && !isspace(buf[i+grouplen])))) + grouplen++; + grouplen++; /* grab the terminator (whitespace for word) */ + if (!itsaword && isspace(buf[i+grouplen])) grouplen++; + if (grouplen < ps->width - ps->linepos) { + nprintbuf(ps, buf, i, grouplen); + } else if (grouplen < ps->width - ps->indent) { + print_ps_indent(ps); + nprintbuf(ps, buf, i, grouplen); + } else { + /* it's just too darn long. what to do? */ + } + i += grouplen; + openquote=openbracket=openparen=openangle=itsaword=PR_FALSE; + } + va_end(args); +} + +void +CMD_PrintUsageString(cmdPrintState *ps, char *str) +{ + nprintf(ps, "%s", str); +} + +/* void because it exits with Usage() if failure */ +static void +command_line_okay(cmdCommand *cmd, char *progName) +{ + int i, c = -1; + /* user asked for help. hope somebody gives it to them. */ + if (cmd->opt[0].on) return; + /* check that the command got all of its needed options */ + for (i=0; i<cmd->ncmd; i++) { + if (cmd->cmd[i].on) { + if (c > 0) { + fprintf(stderr, + "%s: only one command can be given at a time.\n", + progName); + CMD_Usage(progName, cmd); + } else { + c = i; + } + } + } + if (cmd->cmd[c].argUse == CMDArgReq && cmd->cmd[c].arg == NULL) { + /* where's the arg when you need it... */ + fprintf(stderr, "%s: command --%s requires an argument.\n", + progName, cmd->cmd[c].s); + fprintf(stderr, "type \"%s --%s --help\" for help.\n", + progName, cmd->cmd[c].s); + CMD_Usage(progName, cmd); + } + for (i=0; i<cmd->nopt; i++) { + if (cmd->cmd[c].req & CMDBIT(i)) { + /* command requires this option */ + if (!cmd->opt[i].on) { + /* but it ain't there */ + fprintf(stderr, "%s: command --%s requires option --%s.\n", + progName, cmd->cmd[c].s, cmd->opt[i].s); + } else { + /* okay, its there, but does it have an arg? */ + if (cmd->opt[i].argUse == CMDArgReq && !cmd->opt[i].arg) { + fprintf(stderr, "%s: option --%s requires an argument.\n", + progName, cmd->opt[i].s); + } + } + } else if (cmd->cmd[c].opt & CMDBIT(i)) { + /* this option is optional */ + if (cmd->opt[i].on) { + /* okay, its there, but does it have an arg? */ + if (cmd->opt[i].argUse == CMDArgReq && !cmd->opt[i].arg) { + fprintf(stderr, "%s: option --%s requires an argument.\n", + progName, cmd->opt[i].s); + } + } + } else { + /* command knows nothing about it */ + if (cmd->opt[i].on) { + /* so why the h--- is it on? */ + fprintf(stderr, "%s: option --%s not used with command --%s.\n", + progName, cmd->opt[i].s, cmd->cmd[c].s); + } + } + } +} + +static char * +get_arg(char *curopt, char **nextopt, int argc, int *index) +{ + char *str; + if (curopt) { + str = curopt; + } else { + if (*index + 1 >= argc) return NULL; + /* not really an argument but another flag */ + if (nextopt[*index+1][0] == '-') return NULL; + str = nextopt[++(*index)]; + } + /* parse the option */ + return strdup(str); +} + +int +CMD_ParseCommandLine(int argc, char **argv, char *progName, cmdCommand *cmd) +{ + int i, j, k; + int cmdToRun = -1; + char *flag; + i=1; + if (argc <= 1) return -2; /* gross hack for cmdless things like atob */ + do { + flag = argv[i]; + if (strlen(flag) < 2) /* huh? */ + return -1; + if (flag[0] != '-') + return -1; + /* ignore everything after lone "--" (app-specific weirdness there) */ + if (strcmp(flag, "--") == 0) + return cmdToRun; + /* single hyphen means short alias (single-char) */ + if (flag[1] != '-') { + j=1; + /* collect a set of opts, ex. -abc */ + while (flag[j] != '\0') { + PRBool found = PR_FALSE; + /* walk the command set looking for match */ + for (k=0; k<cmd->ncmd; k++) { + if (flag[j] == cmd->cmd[k].c) { + /* done - only take one command at a time */ + if (j > 1) return -1; + cmd->cmd[k].on = found = PR_TRUE; + cmdToRun = k; + if (cmd->cmd[k].argUse != CMDNoArg) + cmd->cmd[k].arg = get_arg(NULL, argv, argc, &i); + goto next_flag; + } + } + /* wasn't found in commands, try options */ + for (k=0; k<cmd->nopt; k++) { + if (flag[j] == cmd->opt[k].c) { + /* collect this option and keep going */ + cmd->opt[k].on = found = PR_TRUE; + if (flag[j+1] == '\0') { + if (cmd->opt[k].argUse != CMDNoArg) + cmd->opt[k].arg = get_arg(NULL, argv, argc, &i); + goto next_flag; + } + } + } + j++; + if (!found) return -1; + } + } else { /* long alias, ex. --list */ + char *fl = NULL, *arg = NULL; + PRBool hyphened = PR_FALSE; + fl = &flag[2]; + arg = strchr(fl, '='); + if (arg) { + *arg++ = '\0'; + } else { + arg = strchr(fl, '-'); + if (arg) { + hyphened = PR_TRUE; /* watch this, see below */ + *arg++ = '\0'; + } + } + for (k=0; k<cmd->ncmd; k++) { + if (strcmp(fl, cmd->cmd[k].s) == 0) { + cmd->cmd[k].on = PR_TRUE; + cmdToRun = k; + if (cmd->cmd[k].argUse != CMDNoArg || hyphened) { + cmd->cmd[k].arg = get_arg(arg, argv, argc, &i); + } + if (arg) arg[-1] = '='; + goto next_flag; + } + } + for (k=0; k<cmd->nopt; k++) { + if (strcmp(fl, cmd->opt[k].s) == 0) { + cmd->opt[k].on = PR_TRUE; + if (cmd->opt[k].argUse != CMDNoArg || hyphened) { + cmd->opt[k].arg = get_arg(arg, argv, argc, &i); + } + if (arg) arg[-1] = '='; + goto next_flag; + } + } + return -1; + } +next_flag: + i++; + } while (i < argc); + command_line_okay(cmd, progName); + return cmdToRun; +} + +void +CMD_LongUsage(char *progName, cmdCommand *cmd, cmdUsageCallback usage) +{ + int i, j; + PRBool oneCommand = PR_FALSE; + cmdPrintState ps; + init_print_ps(&ps, PR_STDERR, 80, 0); + nprintf(&ps, "\n%s: ", progName); + /* prints app-specific header */ + ps.indent = strlen(progName) + 4; + usage(&ps, 0, PR_FALSE, PR_TRUE, PR_FALSE); + for (i=0; i<cmd->ncmd; i++) if (cmd->cmd[i].on) oneCommand = PR_TRUE; + for (i=0; i<cmd->ncmd; i++) { + if ((oneCommand && cmd->cmd[i].on) || !oneCommand) { + ps.indent = 0; + print_ps_indent(&ps); + if (cmd->cmd[i].c != 0) { + nprintf(&ps, "-%c, ", cmd->cmd[i].c); + nprintf(&ps, "--%-16s ", cmd->cmd[i].s); + } else { + nprintf(&ps, "--%-20s ", cmd->cmd[i].s); + } + ps.indent += 20; + usage(&ps, i, PR_TRUE, PR_FALSE, PR_FALSE); + for (j=0; j<cmd->nopt; j++) { + if (cmd->cmd[i].req & CMDBIT(j)) { + ps.indent = 0; + print_ps_indent(&ps); + nprintf(&ps, "%3s* ", ""); + if (cmd->opt[j].c != 0) { + nprintf(&ps, "-%c, ", cmd->opt[j].c); + nprintf(&ps, "--%-16s ", cmd->opt[j].s); + } else { + nprintf(&ps, "--%-20s ", cmd->opt[j].s); + } + ps.indent += 29; + usage(&ps, j, PR_FALSE, PR_FALSE, PR_FALSE); + } + } + for (j=0; j<cmd->nopt; j++) { + if (cmd->cmd[i].opt & CMDBIT(j)) { + ps.indent = 0; + print_ps_indent(&ps); + nprintf(&ps, "%5s", ""); + if (cmd->opt[j].c != 0) { + nprintf(&ps, "-%c, ", cmd->opt[j].c); + nprintf(&ps, "--%-16s ", cmd->opt[j].s); + } else { + nprintf(&ps, "--%-20s ", cmd->opt[j].s); + } + ps.indent += 29; + usage(&ps, j, PR_FALSE, PR_FALSE, PR_FALSE); + } + } + } + nprintf(&ps, "\n"); + } + ps.indent = 0; + nprintf(&ps, "\n* - required flag for command\n\n"); + /* prints app-specific footer */ + usage(&ps, 0, PR_FALSE, PR_FALSE, PR_TRUE); + /*nprintf(&ps, "\n\n");*/ + exit(1); +} + +void +CMD_Usage(char *progName, cmdCommand *cmd) +{ + int i, j, inc; + PRBool first; + cmdPrintState ps; + init_print_ps(&ps, PR_STDERR, 80, 0); + nprintf(&ps, "%s", progName); + ps.indent = strlen(progName) + 1; + print_ps_to_indent(&ps); + for (i=0; i<cmd->ncmd; i++) { + if (cmd->cmd[i].c != 0) { + nprintf(&ps, "-%c", cmd->cmd[i].c); + inc = 4; + } else { + nprintf(&ps, "--%s", cmd->cmd[i].s); + inc = 4 + strlen(cmd->cmd[i].s); + } + first = PR_TRUE; + ps.indent += inc; + print_ps_to_indent(&ps); + for (j=0; j<cmd->nopt; j++) { + if (cmd->cmd[i].req & CMDBIT(j)) { + if (cmd->opt[j].c != 0 && cmd->opt[j].argUse == CMDNoArg) { + if (first) { + nprintf(&ps, "-"); + first = !first; + } + nprintf(&ps, "%c", cmd->opt[j].c); + } + } + } + for (j=0; j<cmd->nopt; j++) { + if (cmd->cmd[i].req & CMDBIT(j)) { + if (cmd->opt[j].c != 0) + nprintf(&ps, "-%c ", cmd->opt[j].c); + else + nprintf(&ps, "--%s ", cmd->opt[j].s); + if (cmd->opt[j].argUse != CMDNoArg) + nprintf(&ps, "%s ", cmd->opt[j].s); + } + } + first = PR_TRUE; + for (j=0; j<cmd->nopt; j++) { + if (cmd->cmd[i].opt & CMDBIT(j)) { + if (cmd->opt[j].c != 0 && cmd->opt[j].argUse == CMDNoArg) { + if (first) { + nprintf(&ps, "[-"); + first = !first; + } + nprintf(&ps, "%c", cmd->opt[j].c); + } + } + } + if (!first) nprintf(&ps, "] "); + for (j=0; j<cmd->nopt; j++) { + if (cmd->cmd[i].opt & CMDBIT(j) && + cmd->opt[j].argUse != CMDNoArg) { + if (cmd->opt[j].c != 0) + nprintf(&ps, "[-%c %s] ", cmd->opt[j].c, cmd->opt[j].s); + else + nprintf(&ps, "[--%s %s] ", cmd->opt[j].s, cmd->opt[j].s); + } + } + ps.indent -= inc; + print_ps_indent(&ps); + } + ps.indent = 0; + nprintf(&ps, "\n"); + exit(1); +} diff --git a/security/nss/cmd/cmdlib/cmdutil.h b/security/nss/cmd/cmdlib/cmdutil.h new file mode 100644 index 000000000..69d3f2657 --- /dev/null +++ b/security/nss/cmd/cmdlib/cmdutil.h @@ -0,0 +1,115 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 _CMDUTIL_H_ +#define _CMDUTIL_H_ + +#include <stdio.h> +#include "nspr.h" +#include "nssbase.h" + +typedef int +(* CMD_PPFunc)(PRFileDesc *out, NSSItem *item, char *msg, int level); + + +/* + * Command Line Parsing routines + * + * The attempt here is to provide common functionality for command line + * parsing across an array of tools. The tools should obey the historical + * rules of: + * + * (1) one command per line, + * (2) the command should be uppercase, + * (3) options should be lowercase, + * (4) a short usage statement is presented in case of error, + * (5) a long usage statement is given by -? or --help + */ + +/* To aid in formatting usage output. XXX Uh, why exposed? */ +typedef struct cmdPrintStateStr cmdPrintState; + +typedef enum { + CMDArgReq = 0, + CMDArgOpt, + CMDNoArg +} CMDArg; + +struct cmdCommandLineArgStr { + char c; /* one-character alias for flag */ + char *s; /* string alias for flag */ + CMDArg argUse; /* flag takes an argument */ + char *arg; /* argument given for flag */ + PRBool on; /* flag was issued at command-line */ + int req; /* required arguments for commands */ + int opt; /* optional arguments for commands */ +}; + +struct cmdCommandLineOptStr { + char c; /* one-character alias for flag */ + char *s; /* string alias for flag */ + CMDArg argUse; /* flag takes an argument */ + char *arg; /* argument given for flag */ + PRBool on; /* flag was issued at command-line */ +}; + +typedef struct cmdCommandLineArgStr cmdCommandLineArg; +typedef struct cmdCommandLineOptStr cmdCommandLineOpt; + +struct cmdCommandStr { + int ncmd; + int nopt; + cmdCommandLineArg *cmd; + cmdCommandLineOpt *opt; +}; + +typedef struct cmdCommandStr cmdCommand; + +int +CMD_ParseCommandLine(int argc, char **argv, char *progName, cmdCommand *cmd); + +typedef void +(* cmdUsageCallback)(cmdPrintState *, int, PRBool, PRBool, PRBool); + +#define CMDBIT(n) (1<<n) + +void +CMD_Usage(char *progName, cmdCommand *cmd); + +void +CMD_LongUsage(char *progName, cmdCommand *cmd, cmdUsageCallback use); + +void +CMD_PrintUsageString(cmdPrintState *ps, char *str); + +#endif /* _CMDUTIL_H_ */ diff --git a/security/nss/cmd/cmdlib/config.mk b/security/nss/cmd/cmdlib/config.mk new file mode 100644 index 000000000..0a00dc61e --- /dev/null +++ b/security/nss/cmd/cmdlib/config.mk @@ -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. +# + +# +# Override TARGETS variable so that only static libraries +# are specifed as dependencies within rules.mk. +# + +TARGETS = $(LIBRARY) +SHARED_LIBRARY = +IMPORT_LIBRARY = +PROGRAM = + diff --git a/security/nss/cmd/cmdlib/manifest.mn b/security/nss/cmd/cmdlib/manifest.mn new file mode 100644 index 000000000..d276bdb23 --- /dev/null +++ b/security/nss/cmd/cmdlib/manifest.mn @@ -0,0 +1,49 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +LIBRARY_NAME = cmdutil + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = seccmd + +DEFINES = -DNSPR20 + +EXPORTS = cmdutil.h \ + $(NULL) + +CSRCS = cmdline.c \ + $(NULL) + +REQUIRES = nss nspr dbm + diff --git a/security/nss/cmd/crlutil/Makefile b/security/nss/cmd/crlutil/Makefile new file mode 100644 index 000000000..573c12cac --- /dev/null +++ b/security/nss/cmd/crlutil/Makefile @@ -0,0 +1,76 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + + +include ../platrules.mk + diff --git a/security/nss/cmd/crlutil/crlutil.c b/security/nss/cmd/crlutil/crlutil.c new file mode 100644 index 000000000..d41dadde7 --- /dev/null +++ b/security/nss/cmd/crlutil/crlutil.c @@ -0,0 +1,478 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* +** certutil.c +** +** utility for managing certificates and the cert database +** +*/ +/* test only */ + +#include "nspr.h" +#include "plgetopt.h" +#include "secutil.h" +#include "cert.h" +#include "certdb.h" +#include "nss.h" +#include "pk11func.h" + +#define SEC_CERT_DB_EXISTS 0 +#define SEC_CREATE_CERT_DB 1 + +static char *progName; + +static CERTSignedCrl *FindCRL + (CERTCertDBHandle *certHandle, char *name, int type) +{ + CERTSignedCrl *crl = NULL; + CERTCertificate *cert = NULL; + + + cert = CERT_FindCertByNickname(certHandle, name); + if (!cert) { + SECU_PrintError(progName, "could not find certificate named %s", name); + return ((CERTSignedCrl *)NULL); + } + + crl = SEC_FindCrlByName(certHandle, &cert->derSubject, type); + if (crl ==NULL) + SECU_PrintError + (progName, "could not find %s's CRL", name); + CERT_DestroyCertificate (cert); + return (crl); +} + +static void DisplayCRL (CERTCertDBHandle *certHandle, char *nickName, int crlType) +{ + CERTCertificate *cert = NULL; + CERTSignedCrl *crl = NULL; + + crl = FindCRL (certHandle, nickName, crlType); + + if (crl) { + SECU_PrintCRLInfo (stdout, &crl->crl, "CRL Info:\n", 0); + SEC_DestroyCrl (crl); + } +} + +static void ListCRLNames (CERTCertDBHandle *certHandle, int crlType, PRBool deletecrls) +{ + CERTCrlHeadNode *crlList = NULL; + CERTCrlNode *crlNode = NULL; + CERTName *name = NULL; + PRArenaPool *arena = NULL; + SECStatus rv; + + do { + arena = PORT_NewArena (SEC_ASN1_DEFAULT_ARENA_SIZE); + if (arena == NULL) { + fprintf(stderr, "%s: fail to allocate memory\n", progName); + break; + } + + name = PORT_ArenaZAlloc (arena, sizeof(*name)); + if (name == NULL) { + fprintf(stderr, "%s: fail to allocate memory\n", progName); + break; + } + name->arena = arena; + + rv = SEC_LookupCrls (certHandle, &crlList, crlType); + if (rv != SECSuccess) { + fprintf(stderr, "%s: fail to look up CRLs (%s)\n", progName, + SECU_Strerror(PORT_GetError())); + break; + } + + /* just in case */ + if (!crlList) + break; + + crlNode = crlList->first; + + fprintf (stdout, "\n"); + fprintf (stdout, "\n%-40s %-5s\n\n", "CRL names", "CRL Type"); + while (crlNode) { + char* asciiname = NULL; + name = &crlNode->crl->crl.name; + if (!name){ + fprintf(stderr, "%s: fail to get the CRL issuer name (%s)\n", progName, + SECU_Strerror(PORT_GetError())); + break; + } + + asciiname = CERT_NameToAscii(name); + fprintf (stdout, "\n%-40s %-5s\n", asciiname, "CRL"); + if (asciiname) { + PORT_Free(asciiname); + } + if ( PR_TRUE == deletecrls) { + CERTSignedCrl* acrl = NULL; + SECItem* issuer = &crlNode->crl->crl.derName; + acrl = SEC_FindCrlByName(certHandle, issuer, crlType); + if (acrl) + { + SEC_DeletePermCRL(acrl); + } + } + crlNode = crlNode->next; + } + + } while (0); + if (crlList) + PORT_FreeArena (crlList->arena, PR_FALSE); + PORT_FreeArena (arena, PR_FALSE); +} + +static void ListCRL (CERTCertDBHandle *certHandle, char *nickName, int crlType) +{ + if (nickName == NULL) + ListCRLNames (certHandle, crlType, PR_FALSE); + else + DisplayCRL (certHandle, nickName, crlType); +} + + + +static SECStatus DeleteCRL (CERTCertDBHandle *certHandle, char *name, int type) +{ + CERTSignedCrl *crl = NULL; + SECStatus rv = SECFailure; + + crl = FindCRL (certHandle, name, type); + if (!crl) { + SECU_PrintError + (progName, "could not find the issuer %s's CRL", name); + return SECFailure; + } + rv = SEC_DeletePermCRL (crl); + if (rv != SECSuccess) { + SECU_PrintError + (progName, "fail to delete the issuer %s's CRL from the perm database (reason: %s)", + name, SECU_Strerror(PORT_GetError())); + return SECFailure; + } + return (rv); +} + +SECStatus ImportCRL (CERTCertDBHandle *certHandle, char *url, int type, + PRFileDesc *inFile, PRInt32 importOptions, PRInt32 decodeOptions) +{ + CERTCertificate *cert = NULL; + CERTSignedCrl *crl = NULL; + SECItem crlDER; + PK11SlotInfo* slot = NULL; + int rv; + PRIntervalTime starttime, endtime, elapsed; + PRUint32 mins, secs, msecs; + + crlDER.data = NULL; + + + /* Read in the entire file specified with the -f argument */ + rv = SECU_ReadDERFromFile(&crlDER, inFile, PR_FALSE); + if (rv != SECSuccess) { + SECU_PrintError(progName, "unable to read input file"); + return (SECFailure); + } + + decodeOptions |= CRL_DECODE_DONT_COPY_DER; + + slot = PK11_GetInternalKeySlot(); + + starttime = PR_IntervalNow(); + crl = PK11_ImportCRL(slot, &crlDER, url, type, + NULL, importOptions, NULL, decodeOptions); + endtime = PR_IntervalNow(); + elapsed = endtime - starttime; + mins = PR_IntervalToSeconds(elapsed) / 60; + secs = PR_IntervalToSeconds(elapsed) % 60; + msecs = PR_IntervalToMilliseconds(elapsed) % 1000; + printf("Elapsed : %2d:%2d.%3d\n", mins, secs, msecs); + if (!crl) { + const char *errString; + + errString = SECU_Strerror(PORT_GetError()); + if ( errString && PORT_Strlen (errString) == 0) + SECU_PrintError + (progName, "CRL is not imported (error: input CRL is not up to date.)"); + else + SECU_PrintError + (progName, "unable to import CRL"); + } + SEC_DestroyCrl (crl); + if (slot) { + PK11_FreeSlot(slot); + } + return (rv); +} + + +static void Usage(char *progName) +{ + fprintf(stderr, + "Usage: %s -L [-n nickname] [-d keydir] [-P dbprefix] [-t crlType]\n" + " %s -D -n nickname [-d keydir] [-P dbprefix]\n" + " %s -I -i crl -t crlType [-u url] [-d keydir] [-P dbprefix] [-B]\n" + " %s -E -t crlType [-d keydir] [-P dbprefix]\n" + " %s -T\n", progName, progName, progName, progName, progName); + + fprintf (stderr, "%-15s List CRL\n", "-L"); + fprintf(stderr, "%-20s Specify the nickname of the CA certificate\n", + "-n nickname"); + fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", + "-d keydir"); + fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n", + "-P dbprefix"); + + fprintf (stderr, "%-15s Delete a CRL from the cert database\n", "-D"); + fprintf(stderr, "%-20s Specify the nickname for the CA certificate\n", + "-n nickname"); + fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType"); + fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", + "-d keydir"); + fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n", + "-P dbprefix"); + + fprintf (stderr, "%-15s Erase all CRLs of specified type from hte cert database\n", "-E"); + fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType"); + fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", + "-d keydir"); + fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n", + "-P dbprefix"); + + fprintf (stderr, "%-15s Import a CRL to the cert database\n", "-I"); + fprintf(stderr, "%-20s Specify the file which contains the CRL to import\n", + "-i crl"); + fprintf(stderr, "%-20s Specify the url.\n", "-u url"); + fprintf(stderr, "%-20s Specify the crl type.\n", "-t crlType"); + fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", + "-d keydir"); + fprintf(stderr, "%-20s Cert & Key database prefix (default is \"\")\n", + "-P dbprefix"); +#ifdef DEBUG + fprintf (stderr, "%-15s Test . Only for debugging purposes. See source code\n", "-T"); +#endif + fprintf(stderr, "%-20s CRL Types (default is SEC_CRL_TYPE):\n", " "); + fprintf(stderr, "%-20s \t 0 - SEC_KRL_TYPE\n", " "); + fprintf(stderr, "%-20s \t 1 - SEC_CRL_TYPE\n", " "); + fprintf(stderr, "\n%-20s Bypass CA certificate checks.\n", "-B"); + fprintf(stderr, "\n%-20s Partial decode for faster operation.\n", "-p"); + fprintf(stderr, "%-20s Repeat the operation.\n", "-r <iterations>"); + + exit(-1); +} + +int main(int argc, char **argv) +{ + SECItem privKeyDER; + CERTCertDBHandle *certHandle; + FILE *certFile; + PRFileDesc *inFile; + int listCRL; + int importCRL; + int deleteCRL; + int rv; + char *nickName; + char *url; + char *dbPrefix = ""; + int crlType; + PLOptState *optstate; + PLOptStatus status; + SECStatus secstatus; + PRBool bypassChecks = PR_FALSE; + PRInt32 decodeOptions = CRL_DECODE_DEFAULT_OPTIONS; + PRInt32 importOptions = CRL_IMPORT_DEFAULT_OPTIONS; + PRBool test = PR_FALSE; + PRBool erase = PR_FALSE; + PRInt32 i = 0; + PRInt32 iterations = 1; + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + rv = 0; + deleteCRL = importCRL = listCRL = 0; + certFile = NULL; + inFile = NULL; + nickName = url = NULL; + privKeyDER.data = NULL; + certHandle = NULL; + crlType = SEC_CRL_TYPE; + /* + * Parse command line arguments + */ + optstate = PL_CreateOptState(argc, argv, "BCDILP:d:i:n:pt:u:TEr:"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case '?': + Usage(progName); + break; + + case 'T': + test = PR_TRUE; + break; + + case 'E': + erase = PR_TRUE; + break; + + case 'B': + importOptions |= CRL_IMPORT_BYPASS_CHECKS; + break; + + case 'C': + listCRL = 1; + break; + + case 'D': + deleteCRL = 1; + break; + + case 'I': + importCRL = 1; + break; + + case 'L': + listCRL = 1; + break; + + case 'P': + dbPrefix = strdup(optstate->value); + break; + + case 'd': + SECU_ConfigDirectory(optstate->value); + break; + + case 'i': + inFile = PR_Open(optstate->value, PR_RDONLY, 0); + if (!inFile) { + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", + progName, optstate->value); + PL_DestroyOptState(optstate); + return -1; + } + break; + + case 'n': + nickName = strdup(optstate->value); + break; + + case 'p': + decodeOptions |= CRL_DECODE_SKIP_ENTRIES; + break; + + case 'r': { + const char* str = optstate->value; + if (str && atoi(str)>0) + iterations = atoi(str); + } + break; + + case 't': { + char *type; + + type = strdup(optstate->value); + crlType = atoi (type); + if (crlType != SEC_CRL_TYPE && crlType != SEC_KRL_TYPE) { + fprintf(stderr, "%s: invalid crl type\n", progName); + PL_DestroyOptState(optstate); + return -1; + } + break; + + case 'u': + url = strdup(optstate->value); + break; + } + } + } + PL_DestroyOptState(optstate); + + if (deleteCRL && !nickName) Usage (progName); + if (!(listCRL || deleteCRL || importCRL || test || erase)) Usage (progName); + if (importCRL && !inFile) Usage (progName); + + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + secstatus = NSS_Initialize(SECU_ConfigDirectory(NULL), dbPrefix, dbPrefix, + "secmod.db", 0); + if (secstatus != SECSuccess) { + SECU_PrintPRandOSError(progName); + return -1; + } + + certHandle = CERT_GetDefaultCertDB(); + if (certHandle == NULL) { + SECU_PrintError(progName, "unable to open the cert db"); + /*ignoring return value of NSS_Shutdown() as code returns -1*/ + (void) NSS_Shutdown(); + return (-1); + } + + for (i=0; i<iterations; i++) { + /* Read in the private key info */ + if (deleteCRL) + DeleteCRL (certHandle, nickName, crlType); + else if (listCRL) { + ListCRL (certHandle, nickName, crlType); + } + else if (importCRL) { + rv = ImportCRL (certHandle, url, crlType, inFile, importOptions, + decodeOptions); + } + else if (erase) { + /* list and delete all CRLs */ + ListCRLNames (certHandle, crlType, PR_TRUE); + } +#ifdef DEBUG + else if (test) { + /* list and delete all CRLs */ + ListCRLNames (certHandle, crlType, PR_TRUE); + /* list CRLs */ + ListCRLNames (certHandle, crlType, PR_FALSE); + /* import CRL as a blob */ + rv = ImportCRL (certHandle, url, crlType, inFile, importOptions, + decodeOptions); + /* list CRLs */ + ListCRLNames (certHandle, crlType, PR_FALSE); + } +#endif + } + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + + return (rv); +} diff --git a/security/nss/cmd/crlutil/makefile.win b/security/nss/cmd/crlutil/makefile.win new file mode 100644 index 000000000..1f1b627ff --- /dev/null +++ b/security/nss/cmd/crlutil/makefile.win @@ -0,0 +1,130 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +VERBOSE = 1 +include <manifest.mn> + +#cannot define PROGRAM in manifest compatibly with NT and UNIX +PROGRAM = crlutil +PROGRAM = ./$(OBJDIR)/$(PROGRAM).exe +include <$(DEPTH)\config\config.mak> + +# let manifest generate C_OBJS, it will prepend ./$(OBJDIR)/ +# rules.mak will append C_OBJS onto OBJS. +# OBJS = $(CSRCS:.c=.obj) + +# include files are looked for in $LINCS and $INCS. +# $LINCS is in manifest.mnw, computed from REQUIRES= +INCS = $(INCS) \ + -I$(DEPTH)/security/lib/cert \ + -I../include \ + $(NULL) + +IGNORE_ME = \ + -I$(DEPTH)/security/lib/key \ + -I$(DEPTH)/security/lib/util \ + $(NULL) + + +WINFE = $(DEPTH)/cmd/winfe/mkfiles$(MOZ_BITS)/x86Dbg + +# these files are the content of libdbm +DBM_LIB = \ + $(WINFE)/DB.obj \ + $(WINFE)/HASH.obj \ + $(WINFE)/H_BIGKEY.obj \ + $(WINFE)/H_PAGE.obj \ + $(WINFE)/H_LOG2.obj \ + $(WINFE)/H_FUNC.obj \ + $(WINFE)/HASH_BUF.obj \ + $(NULL) + +MOZ_LIBS = \ + $(WINFE)/ALLXPSTR.obj \ + $(WINFE)/XP_ERROR.obj \ + $(WINFE)/XPASSERT.obj \ + $(WINFE)/XP_REG.obj \ + $(WINFE)/XP_TRACE.obj \ + $(DBM_LIB) \ + $(WINFE)/XP_STR.obj \ + $(WINFE)/MKTEMP.obj \ + $(NULL) + +SEC_LIBS = \ + $(DIST)/lib/cert$(MOZ_BITS).lib \ + $(DIST)/lib/crypto$(MOZ_BITS).lib \ + $(DIST)/lib/hash$(MOZ_BITS).lib \ + $(DIST)/lib/key$(MOZ_BITS).lib \ + $(DIST)/lib/pkcs7$(MOZ_BITS).lib \ + $(DIST)/lib/secmod$(MOZ_BITS).lib \ + $(DIST)/lib/secutl$(MOZ_BITS).lib \ + $(DIST)/lib/ssl$(MOZ_BITS).lib \ + $(NULL) + +LLFLAGS = $(LLFLAGS) \ + ../lib/$(OBJDIR)/sectool$(MOZ_BITS).lib \ + $(SEC_LIBS) \ + $(MOZ_LIBS) \ + $(DEPTH)/nspr/src/$(OBJDIR)/getopt.obj \ + $(LIBNSPR) \ + $(NULL) + + +include <$(DEPTH)\config\rules.mak> + +INSTALL = $(MAKE_INSTALL) + +objs: $(OBJS) + +$(PROGRAM):: + $(INSTALL) $(DIST)/bin/pr3240.dll ./$(OBJDIR) + +programs: $(PROGRAM) + +install:: $(TARGETS) + $(INSTALL) $(TARGETS) $(DIST)/bin + + +symbols: + @echo "CSRCS = $(CSRCS)" + @echo "INCS = $(INCS)" + @echo "OBJS = $(OBJS)" + @echo "LIBRARY = $(LIBRARY)" + @echo "PROGRAM = $(PROGRAM)" + @echo "TARGETS = $(TARGETS)" + @echo "DIST = $(DIST)" + @echo "VERSION_NUMBER = $(VERSION_NUMBER)" + @echo "WINFE = $(WINFE)" + @echo "DBM_LIB = $(DBM_LIB)" + @echo "INSTALL = $(INSTALL)" + diff --git a/security/nss/cmd/crlutil/manifest.mn b/security/nss/cmd/crlutil/manifest.mn new file mode 100644 index 000000000..169deb28a --- /dev/null +++ b/security/nss/cmd/crlutil/manifest.mn @@ -0,0 +1,53 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +# This next line is used by .mk files +# and gets translated into $LINCS in manifest.mnw +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = seccmd dbm + +DEFINES = -DNSPR20 + +CSRCS = crlutil.c + +# this has to be different for NT and UNIX. +# PROGRAM = ./$(OBJDIR)/crlutil.exe +PROGRAM = crlutil + +#USE_STATIC_LIBS = 1 diff --git a/security/nss/cmd/crmf-cgi/Makefile b/security/nss/cmd/crmf-cgi/Makefile new file mode 100644 index 000000000..23cb6f6b5 --- /dev/null +++ b/security/nss/cmd/crmf-cgi/Makefile @@ -0,0 +1,81 @@ +#! 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). # +####################################################################### +ifeq (,$(filter-out WIN%,$(OS_TARGET))) +EXTRA_LIBS += $(DIST)/lib/crmf.lib +else +EXTRA_LIBS += $(DIST)/lib/libcrmf.$(LIB_SUFFIX) +endif +include manifest.mn + +####################################################################### +# (2) Include "global" configuration information. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +include ../platrules.mk + diff --git a/security/nss/cmd/crmf-cgi/config.mk b/security/nss/cmd/crmf-cgi/config.mk new file mode 100644 index 000000000..bcbaa2804 --- /dev/null +++ b/security/nss/cmd/crmf-cgi/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 = $(PROGRAM) +SHARED_LIBRARY = +IMPORT_LIBRARY = +LIBRARY = + diff --git a/security/nss/cmd/crmf-cgi/crmfcgi.c b/security/nss/cmd/crmf-cgi/crmfcgi.c new file mode 100644 index 000000000..72199cfd5 --- /dev/null +++ b/security/nss/cmd/crmf-cgi/crmfcgi.c @@ -0,0 +1,1124 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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" +#include "nss.h" +#include "key.h" +#include "cert.h" +#include "pk11func.h" +#include "secmod.h" +#include "cmmf.h" +#include "crmf.h" +#include "base64.h" +#include "secasn1.h" +#include "cryptohi.h" +#include <string.h> +#include <stdlib.h> +#include <stdio.h> + +#define DEFAULT_ALLOC_SIZE 200 +#define DEFAULT_CGI_VARS 20 + +typedef struct CGIVariableStr { + char *name; + char *value; +} CGIVariable; + +typedef struct CGIVarTableStr { + CGIVariable **variables; + int numVars; + int numAlloc; +} CGIVarTable; + +typedef struct CertResponseInfoStr { + CERTCertificate *cert; + long certReqID; +} CertResponseInfo; + +typedef struct ChallengeCreationInfoStr { + long random; + SECKEYPublicKey *pubKey; +} ChallengeCreationInfo; + +char *missingVar = NULL; + +/* + * Error values. + */ +typedef enum { + NO_ERROR = 0, + NSS_INIT_FAILED, + AUTH_FAILED, + REQ_CGI_VAR_NOT_PRESENT, + CRMF_REQ_NOT_PRESENT, + BAD_ASCII_FOR_REQ, + CGI_VAR_MISSING, + COULD_NOT_FIND_CA, + COULD_NOT_DECODE_REQS, + OUT_OF_MEMORY, + ERROR_RETRIEVING_REQUEST_MSG, + ERROR_RETRIEVING_CERT_REQUEST, + ERROR_RETRIEVING_SUBJECT_FROM_REQ, + ERROR_RETRIEVING_PUBLIC_KEY_FROM_REQ, + ERROR_CREATING_NEW_CERTIFICATE, + COULD_NOT_START_EXTENSIONS, + ERROR_RETRIEVING_EXT_FROM_REQ, + ERROR_ADDING_EXT_TO_CERT, + ERROR_ENDING_EXTENSIONS, + COULD_NOT_FIND_ISSUER_PRIVATE_KEY, + UNSUPPORTED_SIGN_OPERATION_FOR_ISSUER, + ERROR_SETTING_SIGN_ALG, + ERROR_ENCODING_NEW_CERT, + ERROR_SIGNING_NEW_CERT, + ERROR_CREATING_CERT_REP_CONTENT, + ERROR_CREATING_SINGLE_CERT_RESPONSE, + ERROR_SETTING_CERT_RESPONSES, + ERROR_CREATING_CA_LIST, + ERROR_ADDING_ISSUER_TO_CA_LIST, + ERROR_ENCODING_CERT_REP_CONTENT, + NO_POP_FOR_REQUEST, + UNSUPPORTED_POP, + ERROR_RETRIEVING_POP_SIGN_KEY, + ERROR_RETRIEVING_ALG_ID_FROM_SIGN_KEY, + ERROR_RETRIEVING_SIGNATURE_FROM_POP_SIGN_KEY, + DO_CHALLENGE_RESPONSE, + ERROR_RETRIEVING_PUB_KEY_FROM_NEW_CERT, + ERROR_ENCODING_CERT_REQ_FOR_POP, + ERROR_VERIFYING_SIGNATURE_POP, + ERROR_RETRIEVING_PUB_KEY_FOR_CHALL, + ERROR_CREATING_EMPTY_CHAL_CONTENT, + ERROR_EXTRACTING_GEN_NAME_FROM_ISSUER, + ERROR_SETTING_CHALLENGE, + ERROR_ENCODING_CHALL, + ERROR_CONVERTING_CHALL_TO_BASE64, + ERROR_CONVERTING_RESP_FROM_CHALL_TO_BIN, + ERROR_CREATING_KEY_RESP_FROM_DER, + ERROR_RETRIEVING_CLIENT_RESPONSE_TO_CHALLENGE, + ERROR_RETURNED_CHALL_NOT_VALUE_EXPECTED, + ERROR_GETTING_KEY_ENCIPHERMENT, + ERROR_NO_POP_FOR_PRIVKEY, + ERROR_UNSUPPORTED_POPOPRIVKEY_TYPE +} ErrorCode; + +const char * +CGITableFindValue(CGIVarTable *varTable, const char *key); + +void +spitOutHeaders(void) +{ + printf("Content-type: text/html\n\n"); +} + +void +dumpRequest(CGIVarTable *varTable) +{ + int i; + CGIVariable *var; + + printf ("<table border=1 cellpadding=1 cellspacing=1 width=\"100%%\">\n"); + printf ("<tr><td><b><center>Variable Name<center></b></td>" + "<td><b><center>Value</center></b></td></tr>\n"); + for (i=0; i<varTable->numVars; i++) { + var = varTable->variables[i]; + printf ("<tr><td><pre>%s</pre></td><td><pre>%s</pre></td></tr>\n", + var->name, var->value); + } + printf("</table>\n"); +} + +void +echo_request(CGIVarTable *varTable) +{ + spitOutHeaders(); + printf("<html><head><title>CGI Echo Page</title></head>\n" + "<body><h1>Got the following request</h1>\n"); + dumpRequest(varTable); + printf("</body></html>"); +} + +void +processVariable(CGIVariable *var) +{ + char *plusSign, *percentSign; + + /*First look for all of the '+' and convert them to spaces */ + plusSign = var->value; + while ((plusSign=strchr(plusSign, '+')) != NULL) { + *plusSign = ' '; + } + percentSign = var->value; + while ((percentSign=strchr(percentSign, '%')) != NULL) { + char string[3]; + int value; + + string[0] = percentSign[1]; + string[1] = percentSign[2]; + string[2] = '\0'; + + sscanf(string,"%x", &value); + *percentSign = (char)value; + memmove(&percentSign[1], &percentSign[3], 1+strlen(&percentSign[3])); + } +} + +char * +parseNextVariable(CGIVarTable *varTable, char *form_output) +{ + char *ampersand, *equal; + CGIVariable *var; + + if (varTable->numVars == varTable->numAlloc) { + CGIVariable **newArr = realloc(varTable->variables, + (varTable->numAlloc + DEFAULT_CGI_VARS)*sizeof(CGIVariable*)); + if (newArr == NULL) { + return NULL; + } + varTable->variables = newArr; + varTable->numAlloc += DEFAULT_CGI_VARS; + } + equal = strchr(form_output, '='); + if (equal == NULL) { + return NULL; + } + ampersand = strchr(equal, '&'); + if (ampersand == NULL) { + return NULL; + } + equal[0] = '\0'; + if (ampersand != NULL) { + ampersand[0] = '\0'; + } + var = malloc(sizeof(CGIVariable)); + var->name = form_output; + var->value = &equal[1]; + varTable->variables[varTable->numVars] = var; + varTable->numVars++; + processVariable(var); + return (ampersand != NULL) ? &ersand[1] : NULL; +} + +void +ParseInputVariables(CGIVarTable *varTable, char *form_output) +{ + varTable->variables = malloc(sizeof(CGIVariable*)*DEFAULT_CGI_VARS); + varTable->numVars = 0; + varTable->numAlloc = DEFAULT_CGI_VARS; + while (form_output && form_output[0] != '\0') { + form_output = parseNextVariable(varTable, form_output); + } +} + +const char * +CGITableFindValue(CGIVarTable *varTable, const char *key) +{ + const char *retVal = NULL; + int i; + + for (i=0; i<varTable->numVars; i++) { + if (strcmp(varTable->variables[i]->name, key) == 0) { + retVal = varTable->variables[i]->value; + break; + } + } + return retVal; +} + +char* +passwordCallback(PK11SlotInfo *slot, PRBool retry, void *arg) +{ + const char *passwd; + if (retry) { + return NULL; + } + passwd = CGITableFindValue((CGIVarTable*)arg, "dbPassword"); + if (passwd == NULL) { + return NULL; + } + return PORT_Strdup(passwd); +} + +ErrorCode +initNSS(CGIVarTable *varTable) +{ + const char *nssDir; + PK11SlotInfo *keySlot; + SECStatus rv; + + nssDir = CGITableFindValue(varTable,"NSSDirectory"); + if (nssDir == NULL) { + missingVar = "NSSDirectory"; + return REQ_CGI_VAR_NOT_PRESENT; + } + rv = NSS_Init(nssDir); + if (rv != SECSuccess) { + return NSS_INIT_FAILED; + } + PK11_SetPasswordFunc(passwordCallback); + keySlot = PK11_GetInternalKeySlot(); + rv = PK11_Authenticate(keySlot, PR_FALSE, varTable); + PK11_FreeSlot(keySlot); + if (rv != SECSuccess) { + return AUTH_FAILED; + } + return NO_ERROR; +} + +void +dumpErrorMessage(ErrorCode errNum) +{ + spitOutHeaders(); + printf("<html><head><title>Error</title></head><body><h1>Error processing " + "data</h1> Received the error %d<p>", errNum); + if (errNum == REQ_CGI_VAR_NOT_PRESENT) { + printf ("The missing variable is %s.", missingVar); + } + printf ("<i>More useful information here in the future.</i></body></html>"); +} + +ErrorCode +initOldCertReq(CERTCertificateRequest *oldCertReq, + CERTName *subject, CERTSubjectPublicKeyInfo *spki) +{ + PRArenaPool *poolp; + + poolp = oldCertReq->arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + SEC_ASN1EncodeInteger(poolp, &oldCertReq->version, + SEC_CERTIFICATE_VERSION_3); + CERT_CopyName(poolp, &oldCertReq->subject, subject); + SECKEY_CopySubjectPublicKeyInfo(poolp, &oldCertReq->subjectPublicKeyInfo, + spki); + oldCertReq->attributes = NULL; + return NO_ERROR; +} + +ErrorCode +addExtensions(CERTCertificate *newCert, CRMFCertRequest *certReq) +{ + int numExtensions, i; + void *extHandle; + ErrorCode rv = NO_ERROR; + CRMFCertExtension *ext; + SECStatus srv; + + numExtensions = CRMF_CertRequestGetNumberOfExtensions(certReq); + if (numExtensions == 0) { + /* No extensions to add */ + return NO_ERROR; + } + extHandle = CERT_StartCertExtensions(newCert); + if (extHandle == NULL) { + rv = COULD_NOT_START_EXTENSIONS; + goto loser; + } + for (i=0; i<numExtensions; i++) { + ext = CRMF_CertRequestGetExtensionAtIndex(certReq, i); + if (ext == NULL) { + rv = ERROR_RETRIEVING_EXT_FROM_REQ; + } + srv = CERT_AddExtension(extHandle, CRMF_CertExtensionGetOidTag(ext), + CRMF_CertExtensionGetValue(ext), + CRMF_CertExtensionGetIsCritical(ext), PR_FALSE); + if (srv != SECSuccess) { + rv = ERROR_ADDING_EXT_TO_CERT; + } + } + srv = CERT_FinishExtensions(extHandle); + if (srv != SECSuccess) { + rv = ERROR_ENDING_EXTENSIONS; + goto loser; + } + return NO_ERROR; + loser: + return rv; +} + +void +writeOutItem(const char *filePath, SECItem *der) +{ + PRFileDesc *outfile; + + outfile = PR_Open (filePath, + PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666); + PR_Write(outfile, der->data, der->len); + PR_Close(outfile); + +} + +ErrorCode +createNewCert(CERTCertificate**issuedCert,CERTCertificateRequest *oldCertReq, + CRMFCertReqMsg *currReq, CRMFCertRequest *certReq, + CERTCertificate *issuerCert, CGIVarTable *varTable) +{ + CERTCertificate *newCert = NULL; + CERTValidity *validity; + PRExplodedTime printableTime; + PRTime now, after; + ErrorCode rv=NO_ERROR; + SECKEYPrivateKey *issuerPrivKey; + SECItem derCert = { 0 }; + SECOidTag signTag; + SECStatus srv; + long version; + + now = PR_Now(); + PR_ExplodeTime(now, PR_GMTParameters, &printableTime); + printableTime.tm_month += 9; + after = PR_ImplodeTime(&printableTime); + validity = CERT_CreateValidity(now, after); + newCert = *issuedCert = + CERT_CreateCertificate(rand(), &(issuerCert->subject), validity, + oldCertReq); + if (newCert == NULL) { + rv = ERROR_CREATING_NEW_CERTIFICATE; + goto loser; + } + rv = addExtensions(newCert, certReq); + if (rv != NO_ERROR) { + goto loser; + } + issuerPrivKey = PK11_FindKeyByAnyCert(issuerCert, varTable); + if (issuerPrivKey == NULL) { + rv = COULD_NOT_FIND_ISSUER_PRIVATE_KEY; + } + switch(issuerPrivKey->keyType) { + case rsaKey: + signTag = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; + break; + case dsaKey: + signTag = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; + break; + default: + rv = UNSUPPORTED_SIGN_OPERATION_FOR_ISSUER; + goto loser; + } + srv = SECOID_SetAlgorithmID(newCert->arena, &newCert->signature, + signTag, 0); + if (srv != SECSuccess) { + rv = ERROR_SETTING_SIGN_ALG; + goto loser; + } + srv = CRMF_CertRequestGetCertTemplateVersion(certReq, &version); + if (srv != SECSuccess) { + /* No version included in the request */ + *(newCert->version.data) = SEC_CERTIFICATE_VERSION_3; + } else { + SECITEM_FreeItem(&newCert->version, PR_FALSE); + SEC_ASN1EncodeInteger(newCert->arena, &newCert->version, version); + } + SEC_ASN1EncodeItem(newCert->arena, &derCert, newCert, + CERT_CertificateTemplate); + if (derCert.data == NULL) { + rv = ERROR_ENCODING_NEW_CERT; + goto loser; + } + srv = SEC_DerSignData(newCert->arena, &(newCert->derCert), derCert.data, + derCert.len, issuerPrivKey, signTag); + if (srv != SECSuccess) { + rv = ERROR_SIGNING_NEW_CERT; + goto loser; + } +#ifdef WRITE_OUT_RESPONSE + writeOutItem("newcert.der", &newCert->derCert); +#endif + return NO_ERROR; + loser: + *issuedCert = NULL; + if (newCert) { + CERT_DestroyCertificate(newCert); + } + return rv; + +} + +void +formatCMMFResponse(char *nickname, char *base64Response) +{ + char *currLine, *nextLine; + + printf("var retVal = crypto.importUserCertificates(\"%s\",\n", nickname); + currLine = base64Response; + while (1) { + nextLine = strchr(currLine, '\n'); + if (nextLine == NULL) { + /* print out the last line here. */ + printf ("\"%s\",\n", currLine); + break; + } + nextLine[0] = '\0'; + printf("\"%s\\n\"+\n", currLine); + currLine = nextLine+1; + } + printf("true);\n" + "if(retVal == '') {\n" + "\tdocument.write(\"<h1>New Certificate Succesfully Imported.</h1>\");\n" + "} else {\n" + "\tdocument.write(\"<h2>Unable to import New Certificate</h2>\");\n" + "\tdocument.write(\"crypto.importUserCertificates returned <b>\");\n" + "\tdocument.write(retVal);\n" + "\tdocument.write(\"</b>\");\n" + "}\n"); +} + +void +spitOutCMMFResponse(char *nickname, char *base64Response) +{ + spitOutHeaders(); + printf("<html>\n<head>\n<title>CMMF Resonse Page</title>\n</head>\n\n" + "<body><h1>CMMF Response Page</h1>\n" + "<script language=\"JavaScript\">\n" + "<!--\n"); + formatCMMFResponse(nickname, base64Response); + printf("// -->\n" + "</script>\n</body>\n</html>"); +} + +char* +getNickname(CERTCertificate *cert) +{ + char *nickname; + + if (cert->nickname != NULL) { + return cert->nickname; + } + nickname = CERT_GetCommonName(&cert->subject); + if (nickname != NULL) { + return nickname; + } + return CERT_NameToAscii(&cert->subject); +} + +ErrorCode +createCMMFResponse(CertResponseInfo *issuedCerts, int numCerts, + CERTCertificate *issuerCert, char **base64der) +{ + CMMFCertRepContent *certRepContent=NULL; + ErrorCode rv = NO_ERROR; + CMMFCertResponse **responses, *currResponse; + CERTCertList *caList; + int i; + SECStatus srv; + PRArenaPool *poolp; + SECItem *der; + + certRepContent = CMMF_CreateCertRepContent(); + if (certRepContent == NULL) { + rv = ERROR_CREATING_CERT_REP_CONTENT; + goto loser; + } + responses = PORT_NewArray(CMMFCertResponse*, numCerts); + if (responses == NULL) { + rv = OUT_OF_MEMORY; + goto loser; + } + for (i=0; i<numCerts;i++) { + responses[i] = currResponse = + CMMF_CreateCertResponse(issuedCerts[i].certReqID); + if (currResponse == NULL) { + rv = ERROR_CREATING_SINGLE_CERT_RESPONSE; + goto loser; + } + CMMF_CertResponseSetPKIStatusInfoStatus(currResponse, cmmfGranted); + CMMF_CertResponseSetCertificate(currResponse, issuedCerts[i].cert); + } + srv = CMMF_CertRepContentSetCertResponses(certRepContent, responses, + numCerts); + if (srv != SECSuccess) { + rv = ERROR_SETTING_CERT_RESPONSES; + goto loser; + } + caList = CERT_NewCertList(); + if (caList == NULL) { + rv = ERROR_CREATING_CA_LIST; + goto loser; + } + srv = CERT_AddCertToListTail(caList, issuerCert); + if (srv != SECSuccess) { + rv = ERROR_ADDING_ISSUER_TO_CA_LIST; + goto loser; + } + srv = CMMF_CertRepContentSetCAPubs(certRepContent, caList); + CERT_DestroyCertList(caList); + poolp = PORT_NewArena(1024); + der = SEC_ASN1EncodeItem(poolp, NULL, certRepContent, + CMMFCertRepContentTemplate); + if (der == NULL) { + rv = ERROR_ENCODING_CERT_REP_CONTENT; + goto loser; + } +#ifdef WRITE_OUT_RESPONSE + writeOutItem("CertRepContent.der", der); +#endif + *base64der = BTOA_DataToAscii(der->data, der->len); + return NO_ERROR; + loser: + return rv; +} + +ErrorCode +issueCerts(CertResponseInfo *issuedCerts, int numCerts, + CERTCertificate *issuerCert) +{ + ErrorCode rv; + char *base64Response; + + rv = createCMMFResponse(issuedCerts, numCerts, issuerCert, &base64Response); + if (rv != NO_ERROR) { + goto loser; + } + spitOutCMMFResponse(getNickname(issuedCerts[0].cert),base64Response); + return NO_ERROR; + loser: + return rv; +} + +ErrorCode +verifySignature(CGIVarTable *varTable, CRMFCertReqMsg *currReq, + CRMFCertRequest *certReq, CERTCertificate *newCert) +{ + SECStatus srv; + ErrorCode rv = NO_ERROR; + CRMFPOPOSigningKey *signKey = NULL; + SECAlgorithmID *algID = NULL; + SECItem *signature = NULL; + SECKEYPublicKey *pubKey = NULL; + SECItem *reqDER = NULL; + + srv = CRMF_CertReqMsgGetPOPOSigningKey(currReq, &signKey); + if (srv != SECSuccess || signKey == NULL) { + rv = ERROR_RETRIEVING_POP_SIGN_KEY; + goto loser; + } + algID = CRMF_POPOSigningKeyGetAlgID(signKey); + if (algID == NULL) { + rv = ERROR_RETRIEVING_ALG_ID_FROM_SIGN_KEY; + goto loser; + } + signature = CRMF_POPOSigningKeyGetSignature(signKey); + if (signature == NULL) { + rv = ERROR_RETRIEVING_SIGNATURE_FROM_POP_SIGN_KEY; + goto loser; + } + /* Make the length the number of bytes instead of bits */ + signature->len = (signature->len+7)/8; + pubKey = CERT_ExtractPublicKey(newCert); + if (pubKey == NULL) { + rv = ERROR_RETRIEVING_PUB_KEY_FROM_NEW_CERT; + goto loser; + } + reqDER = SEC_ASN1EncodeItem(NULL, NULL, certReq, CRMFCertRequestTemplate); + if (reqDER == NULL) { + rv = ERROR_ENCODING_CERT_REQ_FOR_POP; + goto loser; + } + srv = VFY_VerifyData(reqDER->data, reqDER->len, pubKey, signature, + SECOID_FindOIDTag(&algID->algorithm), varTable); + if (srv != SECSuccess) { + rv = ERROR_VERIFYING_SIGNATURE_POP; + goto loser; + } + /* Fall thru in successfull case. */ + loser: + if (pubKey != NULL) { + SECKEY_DestroyPublicKey(pubKey); + } + if (reqDER != NULL) { + SECITEM_FreeItem(reqDER, PR_TRUE); + } + if (signature != NULL) { + SECITEM_FreeItem(signature, PR_TRUE); + } + if (algID != NULL) { + SECOID_DestroyAlgorithmID(algID, PR_TRUE); + } + if (signKey != NULL) { + CRMF_DestroyPOPOSigningKey(signKey); + } + return rv; +} + +ErrorCode +doChallengeResponse(CGIVarTable *varTable, CRMFCertReqMsg *currReq, + CRMFCertRequest *certReq, CERTCertificate *newCert, + ChallengeCreationInfo *challs, int *numChall) +{ + CRMFPOPOPrivKey *privKey = NULL; + CRMFPOPOPrivKeyChoice privKeyChoice; + SECStatus srv; + ErrorCode rv = NO_ERROR; + + srv = CRMF_CertReqMsgGetPOPKeyEncipherment(currReq, &privKey); + if (srv != SECSuccess || privKey == NULL) { + rv = ERROR_GETTING_KEY_ENCIPHERMENT; + goto loser; + } + privKeyChoice = CRMF_POPOPrivKeyGetChoice(privKey); + CRMF_DestroyPOPOPrivKey(privKey); + switch (privKeyChoice) { + case crmfSubsequentMessage: + challs = &challs[*numChall]; + challs->random = rand(); + challs->pubKey = CERT_ExtractPublicKey(newCert); + if (challs->pubKey == NULL) { + rv = ERROR_RETRIEVING_PUB_KEY_FOR_CHALL; + goto loser; + } + (*numChall)++; + rv = DO_CHALLENGE_RESPONSE; + break; + case crmfThisMessage: + /* There'd better be a PKIArchiveControl in this message */ + if (!CRMF_CertRequestIsControlPresent(certReq, + crmfPKIArchiveOptionsControl)) { + rv = ERROR_NO_POP_FOR_PRIVKEY; + goto loser; + } + break; + default: + rv = ERROR_UNSUPPORTED_POPOPRIVKEY_TYPE; + goto loser; + } +loser: + return rv; +} + +ErrorCode +doProofOfPossession(CGIVarTable *varTable, CRMFCertReqMsg *currReq, + CRMFCertRequest *certReq, CERTCertificate *newCert, + ChallengeCreationInfo *challs, int *numChall) +{ + CRMFPOPChoice popChoice; + ErrorCode rv = NO_ERROR; + + popChoice = CRMF_CertReqMsgGetPOPType(currReq); + if (popChoice == crmfNoPOPChoice) { + rv = NO_POP_FOR_REQUEST; + goto loser; + } + switch (popChoice) { + case crmfSignature: + rv = verifySignature(varTable, currReq, certReq, newCert); + break; + case crmfKeyEncipherment: + rv = doChallengeResponse(varTable, currReq, certReq, newCert, + challs, numChall); + break; + case crmfRAVerified: + case crmfKeyAgreement: + default: + rv = UNSUPPORTED_POP; + goto loser; + } + loser: + return rv; +} + +void +convertB64ToJS(char *base64) +{ + int i; + + for (i=0; base64[i] != '\0'; i++) { + if (base64[i] == '\n') { + printf ("\\n"); + }else { + printf ("%c", base64[i]); + } + } +} + +void +formatChallenge(char *chall64, char *certRepContentDER, + ChallengeCreationInfo *challInfo, int numChalls) +{ + printf ("function respondToChallenge() {\n" + " var chalForm = document.chalForm;\n\n" + " chalForm.CertRepContent.value = '"); + convertB64ToJS(certRepContentDER); + printf ("';\n" + " chalForm.ChallResponse.value = crypto.popChallengeResponse('"); + convertB64ToJS(chall64); + printf("');\n" + " chalForm.submit();\n" + "}\n"); + +} + +void +spitOutChallenge(char *chall64, char *certRepContentDER, + ChallengeCreationInfo *challInfo, int numChalls, + char *nickname) +{ + int i; + + spitOutHeaders(); + printf("<html>\n" + "<head>\n" + "<title>Challenge Page</title>\n" + "<script language=\"JavaScript\">\n" + "<!--\n"); + /* The JavaScript function actually gets defined within + * this function call + */ + formatChallenge(chall64, certRepContentDER, challInfo, numChalls); + printf("// -->\n" + "</script>\n" + "</head>\n" + "<body onLoad='respondToChallenge()'>\n" + "<h1>Cartman is now responding to the Challenge " + "presented by the CGI</h1>\n" + "<form action='crmfcgi' method='post' name='chalForm'>\n" + "<input type='hidden' name=CertRepContent value=''>\n" + "<input type='hidden' name=ChallResponse value=''>\n"); + for (i=0;i<numChalls; i++) { + printf("<input type='hidden' name='chal%d' value='%d'>\n", + i+1, challInfo[i].random); + } + printf("<input type='hidden' name='nickname' value='%s'>\n", nickname); + printf("</form>\n</body>\n</html>"); +} + +ErrorCode +issueChallenge(CertResponseInfo *issuedCerts, int numCerts, + ChallengeCreationInfo *challInfo, int numChalls, + CERTCertificate *issuer, CGIVarTable *varTable) +{ + ErrorCode rv = NO_ERROR; + CMMFPOPODecKeyChallContent *chalContent = NULL; + int i; + SECStatus srv; + PRArenaPool *poolp; + CERTGeneralName *genName; + SECItem *challDER = NULL; + char *chall64, *certRepContentDER; + + rv = createCMMFResponse(issuedCerts, numCerts, issuer, + &certRepContentDER); + if (rv != NO_ERROR) { + goto loser; + } + chalContent = CMMF_CreatePOPODecKeyChallContent(); + if (chalContent == NULL) { + rv = ERROR_CREATING_EMPTY_CHAL_CONTENT; + goto loser; + } + poolp = PORT_NewArena(1024); + if (poolp == NULL) { + rv = OUT_OF_MEMORY; + goto loser; + } + genName = CERT_GetCertificateNames(issuer, poolp); + if (genName == NULL) { + rv = ERROR_EXTRACTING_GEN_NAME_FROM_ISSUER; + goto loser; + } + for (i=0;i<numChalls;i++) { + srv = CMMF_POPODecKeyChallContentSetNextChallenge(chalContent, + challInfo[i].random, + genName, + challInfo[i].pubKey, + varTable); + SECKEY_DestroyPublicKey(challInfo[i].pubKey); + if (srv != SECSuccess) { + rv = ERROR_SETTING_CHALLENGE; + goto loser; + } + } + challDER = SEC_ASN1EncodeItem(NULL, NULL, chalContent, + CMMFPOPODecKeyChallContentTemplate); + if (challDER == NULL) { + rv = ERROR_ENCODING_CHALL; + goto loser; + } + chall64 = BTOA_DataToAscii(challDER->data, challDER->len); + SECITEM_FreeItem(challDER, PR_TRUE); + if (chall64 == NULL) { + rv = ERROR_CONVERTING_CHALL_TO_BASE64; + goto loser; + } + spitOutChallenge(chall64, certRepContentDER, challInfo, numChalls, + getNickname(issuedCerts[0].cert)); + loser: + return rv; +} + + +ErrorCode +processRequest(CGIVarTable *varTable) +{ + CERTCertDBHandle *certdb; + SECKEYKeyDBHandle *keydb; + CRMFCertReqMessages *certReqs = NULL; + const char *crmfReq; + const char *caNickname; + CERTCertificate *caCert = NULL; + CertResponseInfo *issuedCerts = NULL; + CERTSubjectPublicKeyInfo spki = { 0 }; + ErrorCode rv=NO_ERROR; + PRBool doChallengeResponse = PR_FALSE; + SECItem der = { 0 }; + SECStatus srv; + CERTCertificateRequest oldCertReq = { 0 }; + CRMFCertReqMsg **reqMsgs = NULL,*currReq = NULL; + CRMFCertRequest **reqs = NULL, *certReq = NULL; + CERTName subject = { 0 }; + int numReqs,i; + ChallengeCreationInfo *challInfo=NULL; + int numChalls = 0; + + certdb = CERT_GetDefaultCertDB(); + keydb = SECKEY_GetDefaultKeyDB(); + crmfReq = CGITableFindValue(varTable, "CRMFRequest"); + if (crmfReq == NULL) { + rv = CGI_VAR_MISSING; + missingVar = "CRMFRequest"; + goto loser; + } + caNickname = CGITableFindValue(varTable, "CANickname"); + if (caNickname == NULL) { + rv = CGI_VAR_MISSING; + missingVar = "CANickname"; + goto loser; + } + caCert = CERT_FindCertByNickname(certdb, caNickname); + if (caCert == NULL) { + rv = COULD_NOT_FIND_CA; + goto loser; + } + srv = ATOB_ConvertAsciiToItem(&der, crmfReq); + if (srv != SECSuccess) { + rv = BAD_ASCII_FOR_REQ; + goto loser; + } + certReqs = CRMF_CreateCertReqMessagesFromDER(der.data, der.len); + SECITEM_FreeItem(&der, PR_FALSE); + if (certReqs == NULL) { + rv = COULD_NOT_DECODE_REQS; + goto loser; + } + numReqs = CRMF_CertReqMessagesGetNumMessages(certReqs); + issuedCerts = PORT_ZNewArray(CertResponseInfo, numReqs); + challInfo = PORT_ZNewArray(ChallengeCreationInfo, numReqs); + if (issuedCerts == NULL || challInfo == NULL) { + rv = OUT_OF_MEMORY; + goto loser; + } + reqMsgs = PORT_ZNewArray(CRMFCertReqMsg*, numReqs); + reqs = PORT_ZNewArray(CRMFCertRequest*, numReqs); + if (reqMsgs == NULL || reqs == NULL) { + rv = OUT_OF_MEMORY; + goto loser; + } + for (i=0; i<numReqs; i++) { + currReq = reqMsgs[i] = + CRMF_CertReqMessagesGetCertReqMsgAtIndex(certReqs, i); + if (currReq == NULL) { + rv = ERROR_RETRIEVING_REQUEST_MSG; + goto loser; + } + certReq = reqs[i] = CRMF_CertReqMsgGetCertRequest(currReq); + if (certReq == NULL) { + rv = ERROR_RETRIEVING_CERT_REQUEST; + goto loser; + } + srv = CRMF_CertRequestGetCertTemplateSubject(certReq, &subject); + if (srv != SECSuccess) { + rv = ERROR_RETRIEVING_SUBJECT_FROM_REQ; + goto loser; + } + srv = CRMF_CertRequestGetCertTemplatePublicKey(certReq, &spki); + if (srv != SECSuccess) { + rv = ERROR_RETRIEVING_PUBLIC_KEY_FROM_REQ; + goto loser; + } + rv = initOldCertReq(&oldCertReq, &subject, &spki); + if (rv != NO_ERROR) { + goto loser; + } + rv = createNewCert(&issuedCerts[i].cert, &oldCertReq, currReq, certReq, + caCert, varTable); + if (rv != NO_ERROR) { + goto loser; + } + rv = doProofOfPossession(varTable, currReq, certReq, issuedCerts[i].cert, + challInfo, &numChalls); + if (rv != NO_ERROR) { + if (rv == DO_CHALLENGE_RESPONSE) { + doChallengeResponse = PR_TRUE; + } else { + goto loser; + } + } + CRMF_CertReqMsgGetID(currReq, &issuedCerts[i].certReqID); + CRMF_DestroyCertReqMsg(currReq); + CRMF_DestroyCertRequest(certReq); + } + if (doChallengeResponse) { + rv = issueChallenge(issuedCerts, numReqs, challInfo, numChalls, caCert, + varTable); + } else { + rv = issueCerts(issuedCerts, numReqs, caCert); + } + loser: + if (certReqs != NULL) { + CRMF_DestroyCertReqMessages(certReqs); + } + return rv; +} + +ErrorCode +processChallengeResponse(CGIVarTable *varTable, const char *certRepContent) +{ + SECItem binDER = { 0 }; + SECStatus srv; + ErrorCode rv = NO_ERROR; + const char *clientResponse; + const char *formChalValue; + const char *nickname; + CMMFPOPODecKeyRespContent *respContent = NULL; + int numResponses,i; + long curResponse, expectedResponse; + char cgiChalVar[10]; +#ifdef WRITE_OUT_RESPONSE + SECItem certRepBinDER = { 0 }; + + ATOB_ConvertAsciiToItem(&certRepBinDER, certRepContent); + writeOutItem("challCertRepContent.der", &certRepBinDER); + PORT_Free(certRepBinDER.data); +#endif + clientResponse = CGITableFindValue(varTable, "ChallResponse"); + if (clientResponse == NULL) { + rv = REQ_CGI_VAR_NOT_PRESENT; + missingVar = "ChallResponse"; + goto loser; + } + srv = ATOB_ConvertAsciiToItem(&binDER, clientResponse); + if (srv != SECSuccess) { + rv = ERROR_CONVERTING_RESP_FROM_CHALL_TO_BIN; + goto loser; + } + respContent = CMMF_CreatePOPODecKeyRespContentFromDER(binDER.data, + binDER.len); + SECITEM_FreeItem(&binDER, PR_FALSE); + binDER.data = NULL; + if (respContent == NULL) { + rv = ERROR_CREATING_KEY_RESP_FROM_DER; + goto loser; + } + numResponses = CMMF_POPODecKeyRespContentGetNumResponses(respContent); + for (i=0;i<numResponses;i++){ + srv = CMMF_POPODecKeyRespContentGetResponse(respContent,i,&curResponse); + if (srv != SECSuccess) { + rv = ERROR_RETRIEVING_CLIENT_RESPONSE_TO_CHALLENGE; + goto loser; + } + sprintf(cgiChalVar, "chal%d", i+1); + formChalValue = CGITableFindValue(varTable, cgiChalVar); + if (formChalValue == NULL) { + rv = REQ_CGI_VAR_NOT_PRESENT; + missingVar = strdup(cgiChalVar); + goto loser; + } + sscanf(formChalValue, "%ld", &expectedResponse); + if (expectedResponse != curResponse) { + rv = ERROR_RETURNED_CHALL_NOT_VALUE_EXPECTED; + goto loser; + } + } + nickname = CGITableFindValue(varTable, "nickname"); + if (nickname == NULL) { + rv = REQ_CGI_VAR_NOT_PRESENT; + missingVar = "nickname"; + goto loser; + } + spitOutCMMFResponse(nickname, certRepContent); + loser: + if (respContent != NULL) { + CMMF_DestroyPOPODecKeyRespContent(respContent); + } + return rv; +} + +int +main() +{ + char *form_output = NULL; + int form_output_len, form_output_used; + CGIVarTable varTable = { 0 }; + ErrorCode errNum = 0; + char *certRepContent; + +#ifdef ATTACH_CGI + /* Put an ifinite loop in here so I can attach to + * the process after the process is spun off + */ + { int stupid = 1; + while (stupid); + } +#endif + + form_output_used = 0; + srand(time(NULL)); + while (feof(stdin) == 0) { + if (form_output == NULL) { + form_output = PORT_NewArray(char, DEFAULT_ALLOC_SIZE+1); + form_output_len = DEFAULT_ALLOC_SIZE; + } else if ((form_output_used + DEFAULT_ALLOC_SIZE) >= form_output_len) { + form_output_len += DEFAULT_ALLOC_SIZE; + form_output = PORT_Realloc(form_output, form_output_len+1); + } + form_output_used += fread(&form_output[form_output_used], sizeof(char), + DEFAULT_ALLOC_SIZE, stdin); + } + ParseInputVariables(&varTable, form_output); + certRepContent = CGITableFindValue(&varTable, "CertRepContent"); + if (certRepContent == NULL) { + errNum = initNSS(&varTable); + if (errNum != 0) { + goto loser; + } + errNum = processRequest(&varTable); + } else { + errNum = processChallengeResponse(&varTable, certRepContent); + } + if (errNum != NO_ERROR) { + goto loser; + } + goto done; +loser: + dumpErrorMessage(errNum); +done: + free (form_output); + return 0; +} + diff --git a/security/nss/cmd/crmf-cgi/crmfcgi.html b/security/nss/cmd/crmf-cgi/crmfcgi.html new file mode 100644 index 000000000..e91923ece --- /dev/null +++ b/security/nss/cmd/crmf-cgi/crmfcgi.html @@ -0,0 +1,165 @@ +<!-- + - The contents of this file are subject to the Mozilla Public + - License Version 1.1 (the "License"); you may not use this file + - except in compliance with the License. You may obtain a copy of + - the License at http://www.mozilla.org/MPL/ + - + - Software distributed under the License is distributed on an "AS + - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + - implied. See the License for the specific language governing + - rights and limitations under 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. + --> + +<html> +<head> +<title>CRMF Test Page for PSM</title> +<script language=javascript> +var request; +//This variable must be set to the first value +//in the select field "testType" in the form. +var keyGenType="SigningOnlyRSA"; + +var requestedDN = "CN=Javi CA Shack ID, O=NSS"; + +function setTestType() { + var testType = document.crmfForm.testType; + + keyGenType = testType.options[testType.selectedIndex].value; +} + +function setRequest() { + with (document.crmfForm) { + CRMFRequest.value = request.request; + submit(); + } +} + +function generateSignAndEncryptRSARequest() { + request = crypto.generateCRMFRequest(requestedDN, + null, null, null, "setRequest()", + crypto.algorithms.rsa.keyEx.keySizes[0], + null, "rsa-dual-use"); +} + +function generateSigningOnlyRSARequest() { + request = crypto.generateCRMFRequest(requestedDN,null,null,null,"setRequest()", + crypto.algorithms.rsa.signing.keySizes[0], + null, "rsa-sign"); +} + +function generateEncryptionOnlyRSARequest() { + request = crypto.generateCRMFRequest(requestedDN, null, null, null, "setRequest()", + crypto.algorithms.rsa.keyEx.keySizes[0], + null, "rsa-ex"); +} + +function generateDualRSAKeys() { + request = crypto.generateCRMFRequest(requestedDN, null, null, null, "setRequest()", + crypto.algorithms.rsa.keyEx.keySizes[0], + null, "rsa-ex", + crypto.algorithms.rsa.signing.keySizes[0], + null, "rsa-sign"); +} + +function generateDSAKey() { + request = crypto.generateCRMFRequest(requestedDN, null, null, null, "setRequest()", + crypto.algorithms.dsa.keySizes[0], + null, "dsa-sign-nonrepudiation"); +} + +function processForm(form) { + with (form) { + if (typeof(crypto.version) == "undefined") { + alert('You must be running PSM in order to use this page.'); + return false; + } + if (NSSDirectory.value == "") { + alert('You must provide a path for NSS to use.'); + return false; + } + if (dbPassword.value == "") { + alert('You must provide a password for the certificate database.'); + return false; + } + if (CANickname.value == "") { + alert('You must provide a CA Nickname to use.'); + return false; + } + //Now do the correct key generation. + if (keyGenType == "SignAndEncryptRSA") { + generateSignAndEncryptRSARequest(); + } else if (keyGenType == "SigningOnlyRSA") { + generateSigningOnlyRSARequest(); + } else if (keyGenType == "EncryptionOnlyRSA") { + generateEncryptionOnlyRSARequest(); + } else if (keyGenType == "DualRSAKeys") { + generateDualRSAKeys(); + } else if (keyGenType == "DSAKeyGen") { + generateDSAKey(); + } + } + return true; +} +</script> +</head> +<body> +<h1><center>CRMF Test page for PSM</center></h1> +This page is designed to be used in combination with the executable +produced by ns/security/cmd/crmf-cgi in a CGI environment. In order +to successfully use this page, modify its action to post to a a server +where you have installed the crmfcgi executable and you'll be able to +test the functionality. +<hr> +<form name="crmfForm" method=post action="http://www.cgi-site.com/cgi-bin/crmfcgi"> +<h2>Certificate Database information</h2> +First, enter all the information for the CGI to use for initializing +NSS. The CGI will use the directory entered below as the directory +where to look for the certificate and key databases. +<pre> +Path for NSS Config: <input size=40 type="text" name="NSSDirectory"> +</pre> +Enter the password for the certificate database found in the direcotry +above. +<pre> +Database Password: <input type="password" name="dbPassword" size=40> +</pre> +Now enter the nickname of the certificate to use for signing the +certificate issued during this test. +<pre> +CA Nickname: <input size=40 type="text" name="CANickname"> +</pre> +<h2>Now, figure out which type of key generation you want to test:</h2> +<select name="testType" onChange="setTestType()">` +<option value="SigningOnlyRSA">Signing Only-RSA +<option value="EncryptionOnlyRSA">Encryption Only-RSA +<option value="SignAndEncryptRSA">Sign and Encrypt Single Key -RSA +<option value="DualRSAKeys">Dual Keys-RSA +<option value="DSAKeyGen">DSA Key Gen +</select> +<input type="hidden" name=CRMFRequest value=""> +<hr> +<input type="button" value="OK" onclick="processForm(document.crmfForm)"> +</form> +</body> +</html> diff --git a/security/nss/cmd/crmf-cgi/manifest.mn b/security/nss/cmd/crmf-cgi/manifest.mn new file mode 100644 index 000000000..3a3496327 --- /dev/null +++ b/security/nss/cmd/crmf-cgi/manifest.mn @@ -0,0 +1,61 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. +MODULE = sectools + +EXPORTS = \ + $(NULL) + +CSRCS = \ + crmfcgi.c \ + $(NULL) + + +REQUIRES = nss dbm seccmd + +ifdef ATTACH_CGI +DEFINES += -DATTACH_CGI +endif + +ifdef WRITE_OUT_RESPONSE +DEFINES += -DWRITE_OUT_RESPONSE +endif + +PROGRAM = crmfcgi + +USE_STATIC_LIBS = 1 + +INCLUDES = + +DEFINES = -DNSPR20 diff --git a/security/nss/cmd/crmftest/Makefile b/security/nss/cmd/crmftest/Makefile new file mode 100644 index 000000000..5df669763 --- /dev/null +++ b/security/nss/cmd/crmftest/Makefile @@ -0,0 +1,99 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### +include config.mk + +ifeq ($(OS_TARGET)$(OS_RELEASE), AIX4.2) +OS_LIBS += -lsvld +endif + +ifeq ($(OS_TARGET)$(OS_RELEASE), SunOS5.6) +OS_LIBS += -ldl -lxnet -lposix4 -lsocket -lnsl +endif + +ifeq (,$(filter-out WIN%,$(OS_TARGET))) +EXTRA_LIBS += $(DIST)/lib/crmf.lib +else +EXTRA_LIBS += $(DIST)/lib/libcrmf.$(LIB_SUFFIX) +endif + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +LDDIST = $(DIST)/lib + +ifeq (,$(filter-out WIN%,$(OS_TARGET))) +EXTRA_LIBS += $(LDDIST)/sectool.lib +endif + +lame: + echo $(CPU_ARCH) + +include ../platrules.mk diff --git a/security/nss/cmd/crmftest/config.mk b/security/nss/cmd/crmftest/config.mk new file mode 100644 index 000000000..7343609f8 --- /dev/null +++ b/security/nss/cmd/crmftest/config.mk @@ -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. +# + +# +# Override TARGETS variable so that only static libraries +# are specifed as dependencies within rules.mk. +# + +TARGETS = $(PROGRAM) +SHARED_LIBRARY = +IMPORT_LIBRARY = +LIBRARY = + diff --git a/security/nss/cmd/crmftest/manifest.mn b/security/nss/cmd/crmftest/manifest.mn new file mode 100644 index 000000000..cd5275094 --- /dev/null +++ b/security/nss/cmd/crmftest/manifest.mn @@ -0,0 +1,53 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. +DEPTH = . + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +EXPORTS = \ + $(NULL) + +CSRCS = \ + testcrmf.c \ + $(NULL) + + +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = dbm + +PROGRAM = crmftest + diff --git a/security/nss/cmd/crmftest/testcrmf.c b/security/nss/cmd/crmftest/testcrmf.c new file mode 100644 index 000000000..e9bb08bdb --- /dev/null +++ b/security/nss/cmd/crmftest/testcrmf.c @@ -0,0 +1,1533 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "crmf.h" +#include "secrng.h" +#include "secpkcs5.h" +#include "pk11func.h" +#include "pkcs11.h" +#include "secmod.h" +#include "secmodi.h" +#include "key.h" +#include "prio.h" +#include "pqggen.h" +#include "cmmf.h" +#include "seccomon.h" +#include "secmod.h" +#include "prlock.h" +#include "secmodi.h" +#include "pkcs11.h" +#include "pk11func.h" +#include "secitem.h" +#include "key.h" +#include "rsa.h" +#include "secpkcs5.h" +#include "secasn1.h" +#include "sechash.h" +#include "cert.h" +#include "secerr.h" +#include <stdio.h> +#include "prprf.h" +#if !defined(XP_UNIX) && !defined(LINUX) +extern int getopt(int, char **, char*); +extern char *optarg; +#endif +#define MAX_KEY_LEN 512 + +int64 notBefore; +char *personalCert = NULL; +char *recoveryEncrypter = NULL; +char *caCertName = NULL; + +CERTCertDBHandle *db; +SECKEYKeyDBHandle *keydb; + +void +debug_test(SECItem *src, char *filePath) +{ + PRFileDesc *fileDesc; + + fileDesc = PR_Open (filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666); + if (fileDesc == NULL) { + printf ("Could not cretae file %s.\n", filePath); + return; + } + PR_Write(fileDesc, src->data, src->len); + +} + +SECStatus +get_serial_number(long *dest) +{ + RNGContext *rng; + SECStatus rv; + + if (dest == NULL) { + return SECFailure; + } + rng = RNG_CreateContext(); + if (rng == NULL) { + *dest = 0; + return SECFailure; + } + rv = RNG_GenerateRandomBytes(rng, (void*)dest, sizeof(long)); + RNG_DestroyContext(rng, PR_TRUE); + return SECSuccess; +} + +char * +promptForPassword (PK11SlotInfo *slot, PRBool retry, void *cx) +{ + char passWord[80]; + char *retPass = NULL; + + if (retry) { + printf ("Incorrect password. Please re-enter the password.\n"); + } + printf ("WARNING: Password will be echoed to the screen.\n"); + printf ("Please enter the password for slot \"%s\":", + PK11_GetTokenName(slot)); + scanf ("%s", passWord); + retPass = PORT_Strdup(passWord); + return retPass; +} + +PK11RSAGenParams * +GetRSAParams(void) +{ + PK11RSAGenParams *rsaParams; + + rsaParams = PORT_ZNew(PK11RSAGenParams); + + if (rsaParams == NULL) + return NULL; + + rsaParams->keySizeInBits = MAX_KEY_LEN; + rsaParams->pe = 0x1001; + + return rsaParams; + +} + +SECStatus +SetSlotPassword(PK11SlotInfo *slot) +{ + char userPin[80]; + + printf ("Initialization of PIN's for your Database.\n"); + printf ("------------------------------------------\n"); + printf ("Please enter the PIN's for your Database.\n"); + printf ("Warning: ALL PIN'S WILL BE ECHOED TO SCREEN!!!\n"); + printf ("Now enter the PIN for the user: "); + scanf ("%s", userPin); + return PK11_InitPin (slot, NULL, userPin); +} + +PQGParams* +GetDSAParams(void) +{ + PQGParams *params = NULL; + PQGVerify *vfy = NULL; + + SECStatus rv; + + rv = PQG_ParamGen(0, ¶ms, &vfy); + if (rv != SECSuccess) { + return NULL; + } + PQG_DestroyVerify(vfy); + return params; +} + +CERTSubjectPublicKeyInfo * +GetSubjectPubKeyInfo(SECKEYPrivateKey **destPrivKey, + SECKEYPublicKey **destPubKey) { + CERTSubjectPublicKeyInfo *spki = NULL; + SECKEYPrivateKey *privKey = NULL; + SECKEYPublicKey *pubKey = NULL; + PK11SlotInfo *keySlot = NULL; + PK11SlotInfo *cryptoSlot = NULL; + PK11RSAGenParams *rsaParams = NULL; + PQGParams *dsaParams = NULL; + + keySlot = PK11_GetInternalKeySlot(); + PK11_Authenticate(keySlot, PR_FALSE, NULL); + cryptoSlot = PK11_GetInternalSlot(); + PK11_Authenticate(cryptoSlot, PR_FALSE, NULL); + PK11_FreeSlot(cryptoSlot); + rsaParams = GetRSAParams(); + privKey = PK11_GenerateKeyPair(keySlot, CKM_RSA_PKCS_KEY_PAIR_GEN, + (void*)rsaParams, &pubKey, PR_FALSE, + PR_FALSE, NULL); +/* dsaParams = GetDSAParams(); + if (dsaParams == NULL) { + PK11_FreeSlot(keySlot); + return NULL; + } + privKey = PK11_GenerateKeyPair(keySlot, CKM_DSA_KEY_PAIR_GEN, + (void*)dsaParams, &pubKey, PR_FALSE, + PR_FALSE, NULL);*/ + PK11_FreeSlot(keySlot); + if (privKey == NULL || pubKey == NULL) { + if (pubKey) { + SECKEY_DestroyPublicKey(pubKey); + } + if (privKey) { + SECKEY_DestroyPrivateKey(privKey); + } + return NULL; + } + + spki = SECKEY_CreateSubjectPublicKeyInfo(pubKey); + *destPrivKey = privKey; + *destPubKey = pubKey; + return spki; +} + + +SECStatus +InitPKCS11(void) +{ + PK11SlotInfo *cryptoSlot, *keySlot; + + PK11_SetPasswordFunc(promptForPassword); + + cryptoSlot = PK11_GetInternalSlot(); + keySlot = PK11_GetInternalKeySlot(); + + if (PK11_NeedUserInit(cryptoSlot) && PK11_NeedLogin(cryptoSlot)) { + if (SetSlotPassword (cryptoSlot) != SECSuccess) { + printf ("Initializing the PIN's failed.\n"); + return SECFailure; + } + } + + if (PK11_NeedUserInit(keySlot) && PK11_NeedLogin(keySlot)) { + if (SetSlotPassword (keySlot) != SECSuccess) { + printf ("Initializing the PIN's failed.\n"); + return SECFailure; + } + } + + PK11_FreeSlot(cryptoSlot); + PK11_FreeSlot(keySlot); + return SECSuccess; +} + + +void +WriteItOut (void *arg, const char *buf, unsigned long len) +{ + PRFileDesc *fileDesc = (PRFileDesc*)arg; + + PR_Write(fileDesc, (void*)buf, len); +} + +SECItem +GetRandomBitString(void) +{ +#define NUM_BITS 800 +#define BITS_IN_BYTE 8 + SECItem bitString; + int numBytes = NUM_BITS/BITS_IN_BYTE; + unsigned char *bits = PORT_ZNewArray(unsigned char, numBytes); + RNGContext *rng; + + rng = RNG_CreateContext(); + RNG_GenerateRandomBytes(rng, (void*)bits, numBytes); + RNG_DestroyContext(rng, PR_TRUE); + bitString.data = bits; + bitString.len = NUM_BITS; + bitString.type = siBuffer; + return bitString; +} + +CRMFCertExtCreationInfo* +GetExtensions(void) +{ + CRMFCertExtCreationInfo *extInfo; + CRMFCertExtension *currExt; + CRMFCertExtension *extension; + SECItem data; + PRBool prFalse = PR_FALSE; + unsigned char keyUsage[4]; + + data.len = 4; + data.data = keyUsage; + keyUsage[0] = 0x03; + keyUsage[1] = 0x02; + keyUsage[2] = 0x07; + keyUsage[3] = KU_DIGITAL_SIGNATURE; + extension = CRMF_CreateCertExtension(SEC_OID_X509_KEY_USAGE,prFalse, + &data); + extInfo = PORT_ZNew(CRMFCertExtCreationInfo); + extInfo->numExtensions = 1; + extInfo->extensions = PORT_ZNewArray(CRMFCertExtension*, 1); + extInfo->extensions[0] = extension; + return extInfo; +} + +void +FreeExtInfo(CRMFCertExtCreationInfo *extInfo) +{ + int i; + + for (i=0; i<extInfo->numExtensions; i++) { + CRMF_DestroyCertExtension(extInfo->extensions[i]); + } + PORT_Free(extInfo->extensions); + PORT_Free(extInfo); +} + +int +CreateCertRequest (CRMFCertRequest **inCertReq, SECKEYPrivateKey **privKey, + SECKEYPublicKey **pubKey) +{ + long serialNumber; + long version = 3; + char *issuerStr = PORT_Strdup ("CN=Javi's CA Shack, O=Information Systems"); + char *subjectStr = PORT_Strdup ("CN=Javi's CA Shack ID, O=Engineering, " + "C=US"); + CRMFCertRequest *certReq; + SECAlgorithmID * algID; + CERTName *issuer, *subject; + CRMFValidityCreationInfo validity; + CERTSubjectPublicKeyInfo *spki; + SECStatus rv; + SECOidTag tag, tag2; + SECItem issuerUID, subjectUID; + CRMFCertExtCreationInfo *extInfo; + CRMFEncryptedKey *encKey; + CERTCertificate *caCert; + CRMFPKIArchiveOptions *pkiArchOpt; + + *inCertReq = NULL; + certReq = CRMF_CreateCertRequest(0x0ff02345); + if (certReq == NULL) { + printf ("Could not initialize a certificate request.\n"); + return 1; + } + rv = CRMF_CertRequestSetTemplateField (certReq, crmfVersion, (void*)(&version)); + if (rv != SECSuccess) { + printf("Could not add the version number to the " + "Certificate Request.\n"); + CRMF_DestroyCertRequest(certReq); + return 2; + } + + if (get_serial_number(&serialNumber) != SECSuccess) { + printf ("Could not generate a serial number for cert request.\n"); + CRMF_DestroyCertRequest(certReq); + return 3; + } + + rv = CRMF_CertRequestSetTemplateField (certReq, crmfSerialNumber, + (void*)(&serialNumber)); + if (rv != SECSuccess) { + printf ("Could not add serial number to certificate template\n."); + CRMF_DestroyCertRequest(certReq); + return 4; + } + + issuer = CERT_AsciiToName(issuerStr); + if (issuer == NULL) { + printf ("Could not create CERTName structure from %s.\n", issuerStr); + CRMF_DestroyCertRequest(certReq); + return 5; + } + rv = CRMF_CertRequestSetTemplateField (certReq, crmfIssuer, (void*) issuer); + PORT_Free(issuerStr); + CERT_DestroyName(issuer); + if (rv != SECSuccess) { + printf ("Could not add issuer to cert template\n"); + CRMF_DestroyCertRequest(certReq); + return 6; + } + + subject = CERT_AsciiToName(subjectStr); + if (subject == NULL) { + printf ("Could not create CERTName structure from %s.\n", subjectStr); + CRMF_DestroyCertRequest(certReq); + return 7; + } + PORT_Free(subjectStr); + rv = CRMF_CertRequestSetTemplateField (certReq, crmfSubject, (void*)subject); + if (rv != SECSuccess) { + printf ("Could not add subject to cert template\n"); + CRMF_DestroyCertRequest(certReq); + return 8; + } + CERT_DestroyName(subject); + + algID = + SEC_PKCS5CreateAlgorithmID (SEC_OID_PKCS5_PBE_WITH_SHA1_AND_DES_CBC, + NULL, 1); + if (algID == NULL) { + printf ("Couldn't create algorithm ID\n"); + CRMF_DestroyCertRequest(certReq); + return 9; + } + rv = CRMF_CertRequestSetTemplateField(certReq, crmfSigningAlg, (void*)algID); + SECOID_DestroyAlgorithmID(algID, PR_TRUE); + if (rv != SECSuccess) { + printf ("Could not add the signing algorithm to the cert template.\n"); + CRMF_DestroyCertRequest(certReq); + return 10; + } + + validity.notBefore = ¬Before; + validity.notAfter = NULL; + notBefore = PR_Now(); + rv = CRMF_CertRequestSetTemplateField(certReq, crmfValidity,(void*)(&validity)); + if (rv != SECSuccess) { + printf ("Could not add validity to cert template\n"); + CRMF_DestroyCertRequest(certReq); + return 11; + } + + spki = GetSubjectPubKeyInfo(privKey, pubKey); + if (spki == NULL) { + printf ("Could not create a Subject Public Key Info to add\n"); + CRMF_DestroyCertRequest(certReq); + return 12; + } + rv = CRMF_CertRequestSetTemplateField(certReq, crmfPublicKey, (void*)spki); + SECKEY_DestroySubjectPublicKeyInfo(spki); + if (rv != SECSuccess) { + printf ("Could not add the public key to the template\n"); + CRMF_DestroyCertRequest(certReq); + return 13; + } + + caCert = + CERT_FindCertByNickname(CERT_GetDefaultCertDB(), + caCertName); + if (caCert == NULL) { + printf ("Could not find the certificate for %s\n", caCertName); + CRMF_DestroyCertRequest(certReq); + return 50; + } + + issuerUID = GetRandomBitString(); + subjectUID = GetRandomBitString(); + CRMF_CertRequestSetTemplateField(certReq,crmfIssuerUID, (void*)&issuerUID); + CRMF_CertRequestSetTemplateField(certReq,crmfSubjectUID, (void*)&subjectUID); + PORT_Free(issuerUID.data); + PORT_Free(subjectUID.data); + extInfo = GetExtensions(); + CRMF_CertRequestSetTemplateField(certReq, crmfExtension, (void*)extInfo); + FreeExtInfo(extInfo); + encKey = CRMF_CreateEncryptedKeyWithEncryptedValue(*privKey, caCert); + CERT_DestroyCertificate(caCert); + if (encKey == NULL) { + printf ("Could not create Encrypted Key with Encrypted Value.\n"); + return 14; + } + pkiArchOpt = CRMF_CreatePKIArchiveOptions(crmfEncryptedPrivateKey, encKey); + CRMF_DestroyEncryptedKey(encKey); + if (pkiArchOpt == NULL) { + printf ("Could not create PKIArchiveOptions.\n"); + return 15; + } + rv = CRMF_CertRequestSetPKIArchiveOptions(certReq, pkiArchOpt); + CRMF_DestroyPKIArchiveOptions(pkiArchOpt); + if (rv != SECSuccess) { + printf ("Could not add the PKIArchiveControl to Cert Request.\n"); + return 16; + } + *inCertReq = certReq; + return 0; +} + +int +Encode (CRMFCertReqMsg *inCertReq, + CRMFCertReqMsg *secondReq, char *configdir) +{ +#define PATH_LEN 150 +#define CRMF_FILE "CertReqMessages.der" + char filePath[PATH_LEN]; + PRFileDesc *fileDesc; + SECStatus rv; + int irv = 0; + CRMFCertReqMsg *msgArr[3]; + CRMFCertReqMsg *newMsg; + + PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, CRMF_FILE); + fileDesc = PR_Open (filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666); + if (fileDesc == NULL) { + printf ("Could not open file %s\n", filePath); + irv = 14; + goto finish; + } +/* rv = CRMF_EncodeCertReqMsg (inCertReq, WriteItOut, (void*)fileDesc);*/ + msgArr[0] = inCertReq; + msgArr[1] = secondReq; + msgArr[2] = NULL; + rv = CRMF_EncodeCertReqMessages(msgArr, WriteItOut, (void*)fileDesc); + if (rv != SECSuccess) { + printf ("An error occurred while encoding.\n"); + irv = 15; + goto finish; + } + finish: + PR_Close(fileDesc); + return irv; +} + +int +AddProofOfPossession(CRMFCertReqMsg *certReqMsg, SECKEYPrivateKey *privKey, + SECKEYPublicKey *pubKey, CRMFPOPChoice inPOPChoice) +{ + + switch(inPOPChoice){ + case crmfSignature: + CRMF_CertReqMsgSetSignaturePOP(certReqMsg, privKey, pubKey, NULL, NULL, + NULL); + break; + case crmfRAVerified: + CRMF_CertReqMsgSetRAVerifiedPOP(certReqMsg); + break; + case crmfKeyEncipherment: + CRMF_CertReqMsgSetKeyEnciphermentPOP(certReqMsg, + crmfSubsequentMessage, + crmfChallengeResp, NULL); + break; + case crmfKeyAgreement: + { + SECItem pendejo; + unsigned char lame[] = { 0xf0, 0x0f, 0xf0, 0x0f, 0xf0 }; + + pendejo.data = lame; + pendejo.len = 5; + + CRMF_CertReqMsgSetKeyAgreementPOP(certReqMsg, crmfThisMessage, + crmfNoSubseqMess, &pendejo); + } + break; + default: + return 1; + } + return 0; +} + +#define BUFF_SIZE 150 + +int +Decode(char *configdir) +{ + char filePath[PATH_LEN]; + unsigned char buffer[BUFF_SIZE]; + char *asn1Buff; + PRFileDesc *fileDesc; + PRInt32 fileLen = 0; + PRInt32 bytesRead; + CRMFCertReqMsg *certReqMsg; + CRMFCertRequest *certReq; + CRMFGetValidity validity= {NULL, NULL}; + CRMFCertReqMessages *certReqMsgs; + int numMsgs, i; + long lame; + + PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, CRMF_FILE); + fileDesc = PR_Open(filePath, PR_RDONLY, 0644); + while (1) { + bytesRead = PR_Read(fileDesc, buffer, BUFF_SIZE); + if (bytesRead <= 0) break; + fileLen += bytesRead; + } + if (bytesRead < 0) { + printf ("Error while getting the length of the file %s\n", filePath); + return 200; + } + + PR_Close(fileDesc); + fileDesc = PR_Open(filePath, PR_RDONLY, 0644); + asn1Buff = PORT_ZNewArray(char, fileLen); + bytesRead = PR_Read(fileDesc, asn1Buff, fileLen); + if (bytesRead != fileLen) { + printf ("Error while reading in the contents of %s\n", filePath); + return 201; + } + /*certReqMsg = CRMF_CreateCertReqMsgFromDER(asn1Buff, fileLen); + if (certReqMsg == NULL) { + printf ("Error while decoding the CertReqMsg\n"); + return 202; + } + certReq = CRMF_CertReqMsgGetCertRequest(certReqMsg); +*/ + certReqMsgs = CRMF_CreateCertReqMessagesFromDER(asn1Buff, fileLen); + if (certReqMsgs == NULL) { + printf ("Error decoding CertReqMessages.\n"); + return 202; + } + numMsgs = CRMF_CertReqMessagesGetNumMessages(certReqMsgs); + if (numMsgs <= 0) { + printf ("WARNING: The DER contained %d messages.\n", numMsgs); + } + for (i=0; i < numMsgs; i++) { + certReqMsg = CRMF_CertReqMessagesGetCertReqMsgAtIndex(certReqMsgs, i); + if (certReqMsg == NULL) { + printf ("ERROR: Could not access the message at index %d of %s\n", + i, filePath); + } + CRMF_CertReqMsgGetID(certReqMsg, &lame); + certReq = CRMF_CertReqMsgGetCertRequest(certReqMsg); + CRMF_CertRequestGetCertTemplateValidity(certReq, &validity); + CRMF_DestroyGetValidity(&validity); + CRMF_DestroyCertRequest(certReq); + CRMF_DestroyCertReqMsg(certReqMsg); + } + CRMF_DestroyCertReqMessages(certReqMsgs); + PORT_Free(asn1Buff); + return 0; +} + +void +GetBitsFromFile(char *filePath, SECItem *fileBits) +{ + PRFileDesc *fileDesc; + int bytesRead, fileLen=0; + char buffer[BUFF_SIZE], *asn1Buf; + + fileDesc = PR_Open(filePath, PR_RDONLY, 0644); + while (1) { + bytesRead = PR_Read(fileDesc, buffer, BUFF_SIZE); + if (bytesRead <= 0) break; + fileLen += bytesRead; + } + if (bytesRead < 0) { + printf ("Error while getting the length of file %s.\n", filePath); + goto loser; + } + PR_Close(fileDesc); + + fileDesc = PR_Open(filePath, PR_RDONLY, 0644); + asn1Buf = PORT_ZNewArray(char, fileLen); + if (asn1Buf == NULL) { + printf ("Out of memory in function GetBitsFromFile\n"); + goto loser; + } + bytesRead = PR_Read(fileDesc, asn1Buf, fileLen); + if (bytesRead != fileLen) { + printf ("Error while reading the contents of %s\n", filePath); + goto loser; + } + fileBits->data = (unsigned char*)asn1Buf; + fileBits->len = fileLen; + return; + loser: + if (asn1Buf) { + PORT_Free(asn1Buf); + } + fileBits->data = NULL; + fileBits->len = 0; +} + +int +DecodeCMMFCertRepContent(char *derFile) +{ + int fileLen=0; + char *asn1Buf; + SECItem fileBits; + CMMFCertRepContent *certRepContent; + + + GetBitsFromFile(derFile, &fileBits); + if (fileBits.data == NULL) { + printf("Could not get bits from file %s\n", derFile); + return 304; + } + asn1Buf = (char*)fileBits.data; + fileLen = fileBits.len; + certRepContent = CMMF_CreateCertRepContentFromDER(db, asn1Buf, fileLen); + if (certRepContent == NULL) { + printf ("Error while decoding %s\n", derFile); + return 303; + } + CMMF_DestroyCertRepContent(certRepContent); + PORT_Free(asn1Buf); + return 0; +} + +int +DoCMMFStuff(char *configdir) +{ + CMMFCertResponse *certResp=NULL, *certResp2=NULL, *certResponses[3]; + CMMFCertRepContent *certRepContent=NULL; + CERTCertificate *cert=NULL, *caCert=NULL; + CERTCertList *list=NULL; + PRFileDesc *fileDesc=NULL; + char filePath[PATH_LEN]; + int rv = 0; + long random; + CMMFKeyRecRepContent *repContent=NULL; + SECKEYPrivateKey *privKey = NULL; + SECKEYPublicKey *caPubKey; + SECStatus srv; + SECItem fileBits; + + certResp = CMMF_CreateCertResponse(0xff123); + CMMF_CertResponseSetPKIStatusInfoStatus(certResp, cmmfGranted); + cert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), personalCert); + if (cert == NULL) { + printf ("Could not find the certificate for %s\n", personalCert); + rv = 416; + goto finish; + } + CMMF_CertResponseSetCertificate(certResp, cert); + certResp2 = CMMF_CreateCertResponse(0xff122); + CMMF_CertResponseSetPKIStatusInfoStatus(certResp2, cmmfGranted); + CMMF_CertResponseSetCertificate(certResp2, cert); + + certResponses[0] = certResp; + certResponses[1] = NULL; + certResponses[2] = NULL; + + certRepContent = CMMF_CreateCertRepContent(); + CMMF_CertRepContentSetCertResponses(certRepContent, certResponses, 1); + + list = CERT_GetCertChainFromCert(cert, PR_Now(), certUsageEmailSigner); + CMMF_CertRepContentSetCAPubs(certRepContent, list); + + PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, "CertRepContent.der"); + fileDesc = PR_Open (filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666); + if (fileDesc == NULL) { + printf ("Could not open file %s\n", filePath); + rv = 400; + goto finish; + } + + srv = CMMF_EncodeCertRepContent(certRepContent, WriteItOut, + (void*)fileDesc); + PORT_Assert (srv == SECSuccess); + PR_Close(fileDesc); + rv = DecodeCMMFCertRepContent(filePath); + if (rv != 0) { + goto finish; + } + random = 0xa4e7; + caCert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), + caCertName); + if (caCert == NULL) { + printf ("Could not get the certifcate for %s\n", caCertName); + rv = 411; + goto finish; + } + repContent = CMMF_CreateKeyRecRepContent(); + if (repContent == NULL) { + printf ("Could not allocate a CMMFKeyRecRepContent structure\n"); + rv = 407; + goto finish; + } + srv = CMMF_KeyRecRepContentSetPKIStatusInfoStatus(repContent, + cmmfGrantedWithMods); + if (srv != SECSuccess) { + printf ("Error trying to set PKIStatusInfo for " + "CMMFKeyRecRepContent.\n"); + rv = 406; + goto finish; + } + srv = CMMF_KeyRecRepContentSetNewSignCert(repContent, cert); + if (srv != SECSuccess) { + printf ("Error trying to set the new signing certificate for " + "key recovery\n"); + rv = 408; + goto finish; + } + srv = CMMF_KeyRecRepContentSetCACerts(repContent, list); + if (srv != SECSuccess) { + printf ("Errory trying to add the list of CA certs to the " + "CMMFKeyRecRepContent structure.\n"); + rv = 409; + goto finish; + } + privKey = PK11_FindKeyByAnyCert(cert, NULL); + if (privKey == NULL) { + printf ("Could not get the private key associated with the\n" + "certificate %s\n", personalCert); + rv = 410; + goto finish; + } + caPubKey = CERT_ExtractPublicKey(caCert); + if (caPubKey == NULL) { + printf ("Could not extract the public from the " + "certificate for \n%s\n", caCertName); + rv = 412; + goto finish; + } + CERT_DestroyCertificate(caCert); + caCert = NULL; + srv = CMMF_KeyRecRepContentSetCertifiedKeyPair(repContent, cert, privKey, + caPubKey); + SECKEY_DestroyPrivateKey(privKey); + SECKEY_DestroyPublicKey(caPubKey); + if (srv != SECSuccess) { + printf ("Could not set the Certified Key Pair\n"); + rv = 413; + goto finish; + } + PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, + "KeyRecRepContent.der"); + fileDesc = PR_Open (filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666); + if (fileDesc == NULL) { + printf ("Could not open file %s\n", filePath); + rv = 414; + goto finish; + } + + srv = CMMF_EncodeKeyRecRepContent(repContent, WriteItOut, + (void*)fileDesc); + PORT_Assert (srv == SECSuccess); + PR_Close(fileDesc); + CMMF_DestroyKeyRecRepContent(repContent); + GetBitsFromFile(filePath, &fileBits); + repContent = + CMMF_CreateKeyRecRepContentFromDER(db, (const char *) fileBits.data, + fileBits.len); + if (repContent == NULL) { + printf ("ERROR: CMMF_CreateKeyRecRepContentFromDER failed on file:\n" + "\t%s\n", filePath); + rv = 415; + goto finish; + } + finish: + if (repContent) { + CMMF_DestroyKeyRecRepContent(repContent); + } + if (cert) { + CERT_DestroyCertificate(cert); + } + if (list) { + CERT_DestroyCertList(list); + } + if (certResp) { + CMMF_DestroyCertResponse(certResp); + } + if (certResp2) { + CMMF_DestroyCertResponse(certResp2); + } + if (certRepContent) { + CMMF_DestroyCertRepContent(certRepContent); + } + return rv; +} + +static CK_MECHANISM_TYPE +mapWrapKeyType(KeyType keyType) +{ + switch (keyType) { + case rsaKey: + return CKM_RSA_PKCS; + default: + break; + } + return CKM_INVALID_MECHANISM; +} + +#define KNOWN_MESSAGE_LENGTH 20 /*160 bits*/ + +int +DoKeyRecovery(char *configdir, SECKEYPrivateKey *privKey) +{ + SECKEYPublicKey *pubKey; + PK11SlotInfo *slot; + CK_OBJECT_HANDLE id; + CK_MECHANISM mech = { CKM_INVALID_MECHANISM, NULL, 0}; + unsigned char *known_message = (unsigned char*)"Known Crypto Message"; + unsigned char plaintext[KNOWN_MESSAGE_LENGTH]; + char filePath[PATH_LEN]; + CK_RV crv; + unsigned char *ciphertext; + CK_ULONG max_bytes_encrypted, bytes_encrypted; + unsigned char *text_compared; + CK_ULONG bytes_compared, bytes_decrypted; + SECKEYPrivateKey *unwrappedPrivKey, *caPrivKey; + CMMFKeyRecRepContent *keyRecRep; + SECStatus rv; + CERTCertificate *caCert, *myCert; + SECKEYPublicKey *caPubKey; + PRFileDesc *fileDesc; + SECItem fileBits, nickname; + CMMFCertifiedKeyPair *certKeyPair; + + /*caCert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), + caCertName);*/ + myCert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), personalCert); + if (myCert == NULL) { + printf ("Could not find the certificate for %s\n", personalCert); + return 700; + } + caCert = CERT_FindCertByNickname(CERT_GetDefaultCertDB(), + recoveryEncrypter); + if (caCert == NULL) { + printf ("Could not find the certificate for %s\n", recoveryEncrypter); + return 701; + } + caPubKey = CERT_ExtractPublicKey(caCert); + pubKey = SECKEY_ConvertToPublicKey(privKey); + max_bytes_encrypted = PK11_GetPrivateModulusLen(privKey); + slot = PK11_GetBestSlot(mapWrapKeyType(privKey->keyType), NULL); + id = PK11_ImportPublicKey(slot, pubKey, PR_FALSE); + switch(privKey->keyType) { + case rsaKey: + mech.mechanism = CKM_RSA_PKCS; + break; + case dsaKey: + mech.mechanism = CKM_DSA; + break; + case dhKey: + mech.mechanism = CKM_DH_PKCS_DERIVE; + break; + default: + printf ("Bad Key type in key recovery.\n"); + return 512; + + } + PK11_EnterSlotMonitor(slot); + crv = PK11_GETTAB(slot)->C_EncryptInit(slot->session, &mech, id); + if (crv != CKR_OK) { + PK11_ExitSlotMonitor(slot); + PK11_FreeSlot(slot); + printf ("C_EncryptInit failed in KeyRecovery\n"); + return 500; + } + ciphertext = PORT_NewArray(unsigned char, max_bytes_encrypted); + if (ciphertext == NULL) { + PK11_ExitSlotMonitor(slot); + PK11_FreeSlot(slot); + printf ("Could not allocate memory for ciphertext.\n"); + return 501; + } + bytes_encrypted = max_bytes_encrypted; + crv = PK11_GETTAB(slot)->C_Encrypt(slot->session, + known_message, + KNOWN_MESSAGE_LENGTH, + ciphertext, + &bytes_encrypted); + PK11_ExitSlotMonitor(slot); + PK11_FreeSlot(slot); + if (crv != CKR_OK) { + PORT_Free(ciphertext); + return 502; + } + /* Always use the smaller of these two values . . . */ + bytes_compared = ( bytes_encrypted > KNOWN_MESSAGE_LENGTH ) + ? KNOWN_MESSAGE_LENGTH + : bytes_encrypted; + + /* If there was a failure, the plaintext */ + /* goes at the end, therefore . . . */ + text_compared = ( bytes_encrypted > KNOWN_MESSAGE_LENGTH ) + ? (ciphertext + bytes_encrypted - + KNOWN_MESSAGE_LENGTH ) + : ciphertext; + + keyRecRep = CMMF_CreateKeyRecRepContent(); + if (keyRecRep == NULL) { + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + CMMF_DestroyKeyRecRepContent(keyRecRep); + printf ("Could not allocate a CMMFKeyRecRepContent structre.\n"); + return 503; + } + rv = CMMF_KeyRecRepContentSetPKIStatusInfoStatus(keyRecRep, + cmmfGranted); + if (rv != SECSuccess) { + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + CMMF_DestroyKeyRecRepContent(keyRecRep); + printf ("Could not set the status for the KeyRecRepContent\n"); + return 504; + } + /* The myCert here should correspond to the certificate corresponding + * to the private key, but for this test any certificate will do. + */ + rv = CMMF_KeyRecRepContentSetCertifiedKeyPair(keyRecRep, myCert, + privKey, caPubKey); + if (rv != SECSuccess) { + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + CMMF_DestroyKeyRecRepContent(keyRecRep); + printf ("Could not set the Certified Key Pair\n"); + return 505; + } + PR_snprintf(filePath, PATH_LEN, "%s/%s", configdir, + "KeyRecRepContent.der"); + fileDesc = PR_Open (filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666); + if (fileDesc == NULL) { + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + CMMF_DestroyKeyRecRepContent(keyRecRep); + printf ("Could not open file %s\n", filePath); + return 506; + } + rv = CMMF_EncodeKeyRecRepContent(keyRecRep, WriteItOut, fileDesc); + CMMF_DestroyKeyRecRepContent(keyRecRep); + PR_Close(fileDesc); + + if (rv != SECSuccess) { + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + printf ("Error while encoding CMMFKeyRecRepContent\n"); + return 507; + } + GetBitsFromFile(filePath, &fileBits); + if (fileBits.data == NULL) { + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + printf ("Could not get the bits from file %s\n", filePath); + return 508; + } + keyRecRep = + CMMF_CreateKeyRecRepContentFromDER(db,(const char*)fileBits.data, + fileBits.len); + if (keyRecRep == NULL) { + printf ("Could not decode the KeyRecRepContent in file %s\n", + filePath); + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + return 509; + } + caPrivKey = PK11_FindKeyByAnyCert(caCert, NULL); + if (CMMF_KeyRecRepContentGetPKIStatusInfoStatus(keyRecRep) != + cmmfGranted) { + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + CMMF_DestroyKeyRecRepContent(keyRecRep); + printf ("A bad status came back with the " + "KeyRecRepContent structure\n"); + return 510; + } +#define NICKNAME "Key Recovery Test Key" + nickname.data = (unsigned char*)NICKNAME; + nickname.len = PORT_Strlen(NICKNAME); + certKeyPair = CMMF_KeyRecRepContentGetCertKeyAtIndex(keyRecRep, 0); + CMMF_DestroyKeyRecRepContent(keyRecRep); + rv = CMMF_CertifiedKeyPairUnwrapPrivKey(certKeyPair, + caPrivKey, + &nickname, + PK11_GetInternalKeySlot(), + db, + &unwrappedPrivKey, NULL); + CMMF_DestroyCertifiedKeyPair(certKeyPair); + if (rv != SECSuccess) { + printf ("Unwrapping the private key failed.\n"); + return 511; + } + /*Now let's try to decrypt the ciphertext with the "recovered" key*/ + PK11_EnterSlotMonitor(slot); + crv = + PK11_GETTAB(slot)->C_DecryptInit(unwrappedPrivKey->pkcs11Slot->session, + &mech, + unwrappedPrivKey->pkcs11ID); + if (crv != CKR_OK) { + PK11_ExitSlotMonitor(slot); + PORT_Free(ciphertext); + PK11_FreeSlot(slot); + printf ("Decrypting with the recovered key failed.\n"); + return 513; + } + bytes_decrypted = KNOWN_MESSAGE_LENGTH; + crv = PK11_GETTAB(slot)->C_Decrypt(unwrappedPrivKey->pkcs11Slot->session, + ciphertext, + bytes_encrypted, plaintext, + &bytes_decrypted); + SECKEY_DestroyPrivateKey(unwrappedPrivKey); + PK11_ExitSlotMonitor(slot); + PORT_Free(ciphertext); + if (crv != CKR_OK) { + PK11_FreeSlot(slot); + printf ("Decrypting the ciphertext with recovered key failed.\n"); + return 514; + } + if ((bytes_decrypted != KNOWN_MESSAGE_LENGTH) || + (PORT_Memcmp(plaintext, known_message, KNOWN_MESSAGE_LENGTH) != 0)) { + PK11_FreeSlot(slot); + printf ("The recovered plaintext does not equal the known message:\n" + "\tKnown message: %s\n" + "\tRecovered plaintext: %s\n", known_message, plaintext); + return 515; + } + return 0; +} + +int +DoChallengeResponse(char *configdir, SECKEYPrivateKey *privKey, + SECKEYPublicKey *pubKey) +{ + CMMFPOPODecKeyChallContent *chalContent = NULL; + CMMFPOPODecKeyRespContent *respContent = NULL; + CERTCertificate *myCert = NULL; + CERTGeneralName *myGenName = NULL; + PRArenaPool *poolp = NULL; + SECItem DecKeyChallBits; + long *randomNums; + int numChallengesFound=0; + int numChallengesSet = 1,i; + long retrieved; + char filePath[PATH_LEN]; + RNGContext *rng; + SECStatus rv; + PRFileDesc *fileDesc; + SECItem *publicValue, *keyID; + SECKEYPrivateKey *foundPrivKey; + + chalContent = CMMF_CreatePOPODecKeyChallContent(); + myCert = CERT_FindCertByNickname(db, personalCert); + if (myCert == NULL) { + printf ("Could not find the certificate for %s\n", personalCert); + return 900; + } + poolp = PORT_NewArena(1024); + if (poolp == NULL) { + printf("Could no allocate a new arena in DoChallengeResponse\n"); + return 901; + } + myGenName = CERT_GetCertificateNames(myCert, poolp); + if (myGenName == NULL) { + printf ("Could not get the general names for %s certificate\n", + personalCert); + return 902; + } + randomNums = PORT_ArenaNewArray(poolp,long, numChallengesSet); + rng = RNG_CreateContext(); + RNG_GenerateRandomBytes(rng, randomNums, numChallengesSet*sizeof(long)); + for (i=0; i<numChallengesSet; i++) { + rv = CMMF_POPODecKeyChallContentSetNextChallenge(chalContent, + randomNums[i], + myGenName, + pubKey, + NULL); + } + RNG_DestroyContext(rng, PR_TRUE); + if (rv != SECSuccess) { + printf ("Could not set the challenge in DoChallengeResponse\n"); + return 903; + } + PR_snprintf(filePath, PATH_LEN, "%s/POPODecKeyChallContent.der", + configdir); + fileDesc = PR_Open(filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666); + if (fileDesc == NULL) { + printf ("Could not open file %s\n", filePath); + return 904; + } + rv = CMMF_EncodePOPODecKeyChallContent(chalContent,WriteItOut, + (void*)fileDesc); + PR_Close(fileDesc); + CMMF_DestroyPOPODecKeyChallContent(chalContent); + if (rv != SECSuccess) { + printf ("Could not encode the POPODecKeyChallContent.\n"); + return 905; + } + GetBitsFromFile(filePath, &DecKeyChallBits); + chalContent = + CMMF_CreatePOPODecKeyChallContentFromDER + ((const char*)DecKeyChallBits.data, DecKeyChallBits.len); + PORT_Free(DecKeyChallBits.data); + if (chalContent == NULL) { + printf ("Could not create the POPODecKeyChallContent from DER\n"); + return 906; + } + numChallengesFound = + CMMF_POPODecKeyChallContentGetNumChallenges(chalContent); + if (numChallengesFound != numChallengesSet) { + printf ("Number of Challenges Found (%d) does not equal the number " + "set (%d)\n", numChallengesFound, numChallengesSet); + return 907; + } + for (i=0; i<numChallengesSet; i++) { + publicValue = CMMF_POPODecKeyChallContentGetPublicValue(chalContent, i); + if (publicValue == NULL) { + printf("Could not get the public value for challenge at index %d\n", + i); + return 908; + } + keyID = PK11_MakeIDFromPubKey(publicValue); + if (keyID == NULL) { + printf ("Could not make the keyID from the public value\n"); + return 909; + } + foundPrivKey = PK11_FindKeyByKeyID(privKey->pkcs11Slot,keyID, NULL); + if (foundPrivKey == NULL) { + printf ("Could not find the private key corresponding to the public" + " value.\n"); + return 910; + } + rv = CMMF_POPODecKeyChallContDecryptChallenge(chalContent, i, + foundPrivKey); + if (rv != SECSuccess) { + printf ("Could not decrypt the challenge at index %d\n", i); + return 911; + } + rv = CMMF_POPODecKeyChallContentGetRandomNumber(chalContent, i, + &retrieved); + if (rv != SECSuccess) { + printf ("Could not get the random number from the challenge at " + "index %d\n", i); + return 912; + } + if (retrieved != randomNums[i]) { + printf ("Retrieved the number (%d), expected (%d)\n", retrieved, + randomNums[i]); + return 913; + } + } + CMMF_DestroyPOPODecKeyChallContent(chalContent); + PR_snprintf(filePath, PATH_LEN, "%s/POPODecKeyRespContent.der", + configdir); + fileDesc = PR_Open(filePath, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, + 0666); + if (fileDesc == NULL) { + printf ("Could not open file %s\n", filePath); + return 914; + } + rv = CMMF_EncodePOPODecKeyRespContent(randomNums, numChallengesSet, + WriteItOut, fileDesc); + PR_Close(fileDesc); + if (rv != 0) { + printf ("Could not encode the POPODecKeyRespContent\n"); + return 915; + } + GetBitsFromFile(filePath, &DecKeyChallBits); + respContent = + CMMF_CreatePOPODecKeyRespContentFromDER((const char*)DecKeyChallBits.data, + DecKeyChallBits.len); + if (respContent == NULL) { + printf ("Could not decode the contents of the file %s\n", filePath); + return 916; + } + numChallengesFound = + CMMF_POPODecKeyRespContentGetNumResponses(respContent); + if (numChallengesFound != numChallengesSet) { + printf ("Number of responses found (%d) does not match the number " + "of challenges set (%d)\n", + numChallengesFound, numChallengesSet); + return 917; + } + for (i=0; i<numChallengesSet; i++) { + rv = CMMF_POPODecKeyRespContentGetResponse(respContent, i, &retrieved); + if (rv != SECSuccess) { + printf ("Could not retrieve the response at index %d\n", i); + return 918; + } + if (retrieved != randomNums[i]) { + printf ("Retrieved the number (%ld), expected (%ld)\n", retrieved, + randomNums[i]); + return 919; + } + + } + CMMF_DestroyPOPODecKeyRespContent(respContent); + return 0; +} + +char * +certdb_name_cb(void *arg, int dbVersion) +{ + char *configdir = (char *)arg; + char *dbver; + + switch (dbVersion) { + case 7: + dbver = "7"; + break; + case 6: + dbver = "6"; + break; + case 5: + dbver = "5"; + break; + case 4: + default: + dbver = ""; + break; + } + return PR_smprintf("%s/cert%s.db", configdir, dbver); +} + +SECStatus +OpenCertDB(char *configdir) +{ + CERTCertDBHandle *certdb; + SECStatus status = SECFailure; + + certdb = PORT_ZNew(CERTCertDBHandle); + if (certdb == NULL) { + goto loser; + } + status = CERT_OpenCertDB(certdb, PR_TRUE, certdb_name_cb, configdir); + if (status == SECSuccess) { + CERT_SetDefaultCertDB(certdb); + db = certdb; + } else { + PORT_Free(certdb); + } + loser: + return status; +} + +char * +keydb_name_cb(void *arg, int dbVersion) +{ + char *configdir = (char*) arg; + char *dbver; + + switch(dbVersion){ + case 3: + dbver = "3"; + break; + case 2: + default: + dbver = ""; + break; + } + return PR_smprintf("%s/key%s.db", configdir, dbver); +} + +SECStatus +OpenKeyDB(char *configdir) +{ + SECKEYKeyDBHandle *keydb; + + keydb = SECKEY_OpenKeyDB(PR_FALSE, keydb_name_cb, configdir); + if (keydb == NULL) { + return SECFailure; + } + SECKEY_SetDefaultKeyDB(keydb); + return SECSuccess; +} + +SECStatus +OpenSecModDB(char *configdir) +{ + char *secmodname = PR_smprintf("%d/secmod.db", configdir); + if (secmodname == NULL) { + return SECFailure; + } + SECMOD_init(secmodname); + return SECSuccess; +} + +void +CloseHCL(void) +{ + CERTCertDBHandle *certHandle; + SECKEYKeyDBHandle *keyHandle; + + certHandle = CERT_GetDefaultCertDB(); + if (certHandle) { + CERT_ClosePermCertDB(certHandle); + } + keyHandle = SECKEY_GetDefaultKeyDB(); + if (keyHandle) { + SECKEY_CloseKeyDB(keyHandle); + } +} + +SECStatus +InitHCL(char *configdir) +{ + SECStatus status; + SECStatus rv = SECFailure; + + RNG_RNGInit(); + RNG_SystemInfoForRNG(); + + status = OpenCertDB(configdir); + if (status != SECSuccess) { + goto loser; + } + + status = OpenKeyDB(configdir); + if (status != SECSuccess) { + goto loser; + } + + status = OpenSecModDB(configdir); + if (status != SECSuccess) { + goto loser; + } + + rv = SECSuccess; + + loser: + if (rv != SECSuccess) { + CloseHCL(); + } + return rv; +} +void +Usage (void) +{ + printf ("Usage:\n" + "\tcrmftest -d [Database Directory] -p [Personal Cert]\n" + "\t -e [Encrypter] -s [CA Certificate]\n\n" + "Database Directory\n" + "\tThis is the directory where the key3.db, cert7.db, and\n" + "\tsecmod.db files are located. This is also the directory\n" + "\twhere the program will place CRMF/CMMF der files\n" + "Personal Cert\n" + "\tThis is the certificate that already exists in the cert\n" + "\tdatabase to use while encoding the response. The private\n" + "\tkey associated with the certificate must also exist in the\n" + "\tkey database.\n" + "Encrypter\n" + "\tThis is the certificate to use when encrypting the the \n" + "\tkey recovery response. The private key for this cert\n" + "\tmust also be present in the key database.\n" + "CA Certificate\n" + "\tThis is the nickname of the certificate to use as the\n" + "\tCA when doing all of the encoding.\n"); +} + +int +main(int argc, char **argv) +{ + CRMFCertRequest *certReq, *certReq2; + CRMFCertReqMsg *certReqMsg; + CRMFCertReqMsg *secondMsg; + char *configdir; + int irv; + SECStatus rv; + SECKEYPrivateKey *privKey; + SECKEYPublicKey *pubKey; + int o; + PRBool hclInit = PR_FALSE, pArg = PR_FALSE, eArg = PR_FALSE, + sArg = PR_FALSE; + + printf ("\ncrmftest v1.0\n"); + while (-1 != (o = getopt(argc, argv, "d:p:e:s:"))) { + switch(o) { + case 'd': + configdir = PORT_Strdup(optarg); + rv = InitHCL(configdir); + if (rv != SECSuccess) { + printf ("InitHCL failed\n"); + return 101; + } + hclInit = PR_TRUE; + break; + case 'p': + personalCert = PORT_Strdup(optarg); + if (personalCert == NULL) { + return 603; + } + pArg = PR_TRUE; + break; + case 'e': + recoveryEncrypter = PORT_Strdup(optarg); + if (recoveryEncrypter == NULL) { + return 602; + } + eArg = PR_TRUE; + break; + case 's': + caCertName = PORT_Strdup(optarg); + if (caCertName == NULL) { + return 604; + } + sArg = PR_TRUE; + break; + default: + Usage(); + return 601; + } + } + if (!hclInit || !pArg || !eArg || !sArg) { + Usage(); + return 600; + } + + InitPKCS11(); + + irv = CreateCertRequest(&certReq, &privKey, &pubKey); + if (irv != 0 || certReq == NULL) { + goto loser; + } + + certReqMsg = CRMF_CreateCertReqMsg(); + secondMsg = CRMF_CreateCertReqMsg(); + CRMF_CertReqMsgSetCertRequest(certReqMsg, certReq); + CRMF_CertReqMsgSetCertRequest(secondMsg, certReq); + + irv = AddProofOfPossession(certReqMsg, privKey, pubKey, crmfSignature); + irv = AddProofOfPossession(secondMsg, privKey, pubKey, crmfKeyAgreement); + irv = Encode (certReqMsg, secondMsg, configdir); + if (irv != 0) { + goto loser; + } + + rv = CRMF_DestroyCertRequest (certReq); + if (rv != SECSuccess) { + printf ("Error when destroy certificate request.\n"); + irv = 100; + goto loser; + } + + rv = CRMF_DestroyCertReqMsg(certReqMsg); + CRMF_DestroyCertReqMsg(secondMsg); + + irv = Decode (configdir); + if (irv != 0) { + printf("Error while decoding\n"); + goto loser; + } + + if ((irv = DoCMMFStuff(configdir)) != 0) { + printf ("CMMF tests failed.\n"); + goto loser; + } + + if ((irv = DoKeyRecovery(configdir, privKey)) != 0) { + printf ("Error doing key recovery\n"); + goto loser; + } + + if ((irv = DoChallengeResponse(configdir, privKey, pubKey)) != 0) { + printf ("Error doing challenge-response\n"); + goto loser; + } + printf ("Exiting successfully!!!\n\n"); + irv = 0; + + loser: + CloseHCL(); + PORT_Free(configdir); + return irv; +} diff --git a/security/nss/cmd/dbck/Makefile b/security/nss/cmd/dbck/Makefile new file mode 100644 index 000000000..7ca8f0630 --- /dev/null +++ b/security/nss/cmd/dbck/Makefile @@ -0,0 +1,75 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/dbck/dbck.c b/security/nss/cmd/dbck/dbck.c new file mode 100644 index 000000000..a3f1b9d54 --- /dev/null +++ b/security/nss/cmd/dbck/dbck.c @@ -0,0 +1,1869 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* +** dbck.c +** +** utility for fixing corrupt cert databases +** +*/ +#include <stdio.h> +#include <string.h> + +#include "secutil.h" +#include "cdbhdl.h" +#include "certdb.h" +#include "cert.h" +#include "nspr.h" +#include "prtypes.h" +#include "prtime.h" +#include "prlong.h" + +static char *progName; + +/* placeholders for pointer error types */ +static void *WrongEntry; +static void *NoNickname; +static void *NoSMime; + +enum { + GOBOTH = 0, + GORIGHT, + GOLEFT +}; + +typedef struct +{ + PRBool verbose; + PRBool dograph; + PRFileDesc *out; + PRFileDesc *graphfile; + int dbErrors[10]; +} dbDebugInfo; + +/* + * A list node for a cert db entry. The index is a unique identifier + * to use for creating generic maps of a db. This struct handles + * the cert, nickname, and smime db entry types, as all three have a + * single handle to a subject entry. + * This structure is pointed to by certDBEntryListNode->appData. + */ +typedef struct +{ + PRArenaPool *arena; + int index; + certDBEntryListNode *pSubject; +} certDBEntryMap; + +/* + * Subject entry is special case, it has bidirectional handles. One + * subject entry can point to several certs (using the same DN), and + * a nickname and/or smime entry. + * This structure is pointed to by certDBEntryListNode->appData. + */ +typedef struct +{ + PRArenaPool *arena; + int index; + int numCerts; + certDBEntryListNode **pCerts; + certDBEntryListNode *pNickname; + certDBEntryListNode *pSMime; +} certDBSubjectEntryMap; + +/* + * A map of a certdb. + */ +typedef struct +{ + int numCerts; + int numSubjects; + int numNicknames; + int numSMime; + certDBEntryListNode certs; /* pointer to head of cert list */ + certDBEntryListNode subjects; /* pointer to head of subject list */ + certDBEntryListNode nicknames; /* pointer to head of nickname list */ + certDBEntryListNode smime; /* pointer to head of smime list */ +} certDBArray; + +/* Cast list to the base element, a certDBEntryListNode. */ +#define LISTNODE_CAST(node) \ + ((certDBEntryListNode *)(node)) + +static void +Usage(char *progName) +{ +#define FPS fprintf(stderr, + FPS "Type %s -H for more detailed descriptions\n", progName); + FPS "Usage: %s -D [-d certdir] [-i dbname] [-m] [-v [-f dumpfile]]\n", + progName); + FPS " %s -R -o newdbname [-d certdir] [-i dbname] [-aprsx] [-v [-f dumpfile]]\n", + progName); + exit(-1); +} + +static void +LongUsage(char *progName) +{ + FPS "%-15s Display this help message.\n", + "-H"); + FPS "%-15s Dump analysis. No changes will be made to the database.\n", + "-D"); + FPS "%-15s Cert database directory (default is ~/.netscape)\n", + " -d certdir"); + FPS "%-15s Input cert database name (default is cert7.db)\n", + " -i dbname"); + FPS "%-15s Mail a graph of the database to certdb@netscape.com.\n", + " -m"); + FPS "%-15s This will produce an index graph of your cert db and send\n", + ""); + FPS "%-15s it to Netscape for analysis. Personal info will be removed.\n", + ""); + FPS "%-15s Verbose mode. Dumps the entire contents of your cert7.db.\n", + " -v"); + FPS "%-15s File to dump verbose output into.\n", + " -f dumpfile"); + FPS "%-15s Repair the database. The program will look for broken\n", + "-R"); + FPS "%-15s dependencies between subject entries and certificates,\n", + ""); + FPS "%-15s between nickname entries and subjects, and between SMIME\n", + ""); + FPS "%-15s profiles and subjects. Any duplicate entries will be\n", + ""); + FPS "%-15s removed, any missing entries will be created.\n", + ""); + FPS "%-15s File to store new database in (default is new_cert7.db)\n", + " -o newdbname"); + FPS "%-15s Cert database directory (default is ~/.netscape)\n", + " -d certdir"); + FPS "%-15s Input cert database name (default is cert7.db)\n", + " -i dbname"); + FPS "%-15s Prompt before removing any certificates.\n", + " -p"); + FPS "%-15s Keep all possible certificates. Only remove certificates\n", + " -a"); + FPS "%-15s which prevent creation of a consistent database. Thus any\n", + ""); + FPS "%-15s expired or redundant entries will be kept.\n", + ""); + FPS "%-15s Keep redundant nickname/email entries. It is possible\n", + " -r"); + FPS "%-15s only one such entry will be usable.\n", + ""); + FPS "%-15s Don't require an S/MIME profile in order to keep an S/MIME\n", + " -s"); + FPS "%-15s cert. An empty profile will be created.\n", + ""); + FPS "%-15s Keep expired certificates.\n", + " -x"); + FPS "%-15s Verbose mode - report all activity while recovering db.\n", + " -v"); + FPS "%-15s File to dump verbose output into.\n", + " -f dumpfile"); + FPS "\n"); + exit(-1); +#undef FPS +} + +/******************************************************************* + * + * Functions for dbck. + * + ******************************************************************/ + +void +printHexString(PRFileDesc *out, SECItem *hexval) +{ + int i; + for (i = 0; i < hexval->len; i++) { + if (i != hexval->len - 1) { + PR_fprintf(out, "%02x:", hexval->data[i]); + } else { + PR_fprintf(out, "%02x", hexval->data[i]); + } + } + PR_fprintf(out, "\n"); +} + +typedef enum { +/* 0*/ NoSubjectForCert = 0, +/* 1*/ SubjectHasNoKeyForCert, +/* 2*/ NoNicknameOrSMimeForSubject, +/* 3*/ WrongNicknameForSubject, +/* 4*/ NoNicknameEntry, +/* 5*/ WrongSMimeForSubject, +/* 6*/ NoSMimeEntry, +/* 7*/ NoSubjectForNickname, +/* 8*/ NoSubjectForSMime, +/* 9*/ NicknameAndSMimeEntry +} dbErrorType; + +static char *dbErrorString[] = { +/* 0*/ "<CERT ENTRY>\nDid not find a subject entry for this certificate.", +/* 1*/ "<SUBJECT ENTRY>\nSubject has certKey which is not in db.", +/* 2*/ "<SUBJECT ENTRY>\nSubject does not have a nickname or email address.", +/* 3*/ "<SUBJECT ENTRY>\nUsing this subject's nickname, found a nickname entry for a different subject.", +/* 4*/ "<SUBJECT ENTRY>\nDid not find a nickname entry for this subject.", +/* 5*/ "<SUBJECT ENTRY>\nUsing this subject's email, found an S/MIME entry for a different subject.", +/* 6*/ "<SUBJECT ENTRY>\nDid not find an S/MIME entry for this subject.", +/* 7*/ "<NICKNAME ENTRY>\nDid not find a subject entry for this nickname.", +/* 8*/ "<S/MIME ENTRY>\nDid not find a subject entry for this S/MIME profile.", +}; + +SECStatus +dumpCertificate(CERTCertificate *cert, int num, PRFileDesc *outfile) +{ + int userCert = 0; + CERTCertTrust *trust = cert->trust; + userCert = (SEC_GET_TRUST_FLAGS(trust, trustSSL) & CERTDB_USER) || + (SEC_GET_TRUST_FLAGS(trust, trustEmail) & CERTDB_USER) || + (SEC_GET_TRUST_FLAGS(trust, trustObjectSigning) & CERTDB_USER); + if (num >= 0) { + PR_fprintf(outfile, "Certificate: %3d\n", num); + } else { + PR_fprintf(outfile, "Certificate:\n"); + } + PR_fprintf(outfile, "----------------\n"); + if (userCert) + PR_fprintf(outfile, "(User Cert)\n"); + PR_fprintf(outfile, "## SUBJECT: %s\n", cert->subjectName); + PR_fprintf(outfile, "## ISSUER: %s\n", cert->issuerName); + PR_fprintf(outfile, "## SERIAL NUMBER: "); + printHexString(outfile, &cert->serialNumber); + { /* XXX should be separate function. */ + int64 timeBefore, timeAfter; + PRExplodedTime beforePrintable, afterPrintable; + char *beforestr, *afterstr; + DER_UTCTimeToTime(&timeBefore, &cert->validity.notBefore); + DER_UTCTimeToTime(&timeAfter, &cert->validity.notAfter); + PR_ExplodeTime(timeBefore, PR_GMTParameters, &beforePrintable); + PR_ExplodeTime(timeAfter, PR_GMTParameters, &afterPrintable); + beforestr = PORT_Alloc(100); + afterstr = PORT_Alloc(100); + PR_FormatTime(beforestr, 100, "%a %b %d %H:%M:%S %Y", &beforePrintable); + PR_FormatTime(afterstr, 100, "%a %b %d %H:%M:%S %Y", &afterPrintable); + PR_fprintf(outfile, "## VALIDITY: %s to %s\n", beforestr, afterstr); + } + PR_fprintf(outfile, "\n"); + return SECSuccess; +} + +SECStatus +dumpCertEntry(certDBEntryCert *entry, int num, PRFileDesc *outfile) +{ + CERTCertificate *cert; + cert = CERT_DecodeDERCertificate(&entry->derCert, PR_FALSE, NULL); + if (!cert) { + fprintf(stderr, "Failed to decode certificate.\n"); + return SECFailure; + } + cert->trust = &entry->trust; + dumpCertificate(cert, num, outfile); + CERT_DestroyCertificate(cert); + return SECSuccess; +} + +SECStatus +dumpSubjectEntry(certDBEntrySubject *entry, int num, PRFileDesc *outfile) +{ + char *subjectName; + subjectName = CERT_DerNameToAscii(&entry->derSubject); + PR_fprintf(outfile, "Subject: %3d\n", num); + PR_fprintf(outfile, "------------\n"); + PR_fprintf(outfile, "## %s\n", subjectName); + if (entry->nickname) + PR_fprintf(outfile, "## Subject nickname: %s\n", entry->nickname); + if (entry->emailAddr) + PR_fprintf(outfile, "## Subject email address: %s\n", + entry->emailAddr); + PR_fprintf(outfile, "## This subject has %d cert(s).\n", entry->ncerts); + PR_fprintf(outfile, "\n"); + PORT_Free(subjectName); + return SECSuccess; +} + +SECStatus +dumpNicknameEntry(certDBEntryNickname *entry, int num, PRFileDesc *outfile) +{ + PR_fprintf(outfile, "Nickname: %3d\n", num); + PR_fprintf(outfile, "-------------\n"); + PR_fprintf(outfile, "## \"%s\"\n\n", entry->nickname); + return SECSuccess; +} + +SECStatus +dumpSMimeEntry(certDBEntrySMime *entry, int num, PRFileDesc *outfile) +{ + PR_fprintf(outfile, "S/MIME Profile: %3d\n", num); + PR_fprintf(outfile, "-------------------\n"); + PR_fprintf(outfile, "## \"%s\"\n", entry->emailAddr); + PR_fprintf(outfile, "## OPTIONS: "); + printHexString(outfile, &entry->smimeOptions); + PR_fprintf(outfile, "## TIMESTAMP: "); + printHexString(outfile, &entry->optionsDate); + PR_fprintf(outfile, "\n"); + return SECSuccess; +} + +SECStatus +mapCertEntries(certDBArray *dbArray) +{ + certDBEntryCert *certEntry; + certDBEntrySubject *subjectEntry; + certDBEntryListNode *certNode, *subjNode; + certDBSubjectEntryMap *smap; + certDBEntryMap *map; + PRArenaPool *tmparena; + SECItem derSubject; + SECItem certKey; + PRCList *cElem, *sElem; + int i; + + /* Arena for decoded entries */ + tmparena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (tmparena == NULL) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return SECFailure; + } + + /* Iterate over cert entries and map them to subject entries. + * NOTE: mapSubjectEntries must be called first to alloc memory + * for array of subject->cert map. + */ + for (cElem = PR_LIST_HEAD(&dbArray->certs.link); + cElem != &dbArray->certs.link; cElem = PR_NEXT_LINK(cElem)) { + certNode = LISTNODE_CAST(cElem); + certEntry = (certDBEntryCert *)&certNode->entry; + map = (certDBEntryMap *)certNode->appData; + CERT_NameFromDERCert(&certEntry->derCert, &derSubject); + CERT_KeyFromDERCert(tmparena, &certEntry->derCert, &certKey); + /* Loop over found subjects for cert's DN. */ + for (sElem = PR_LIST_HEAD(&dbArray->subjects.link); + sElem != &dbArray->subjects.link; sElem = PR_NEXT_LINK(sElem)) { + subjNode = LISTNODE_CAST(sElem); + subjectEntry = (certDBEntrySubject *)&subjNode->entry; + if (SECITEM_ItemsAreEqual(&derSubject, &subjectEntry->derSubject)) { + /* Found matching subject name, create link. */ + map->pSubject = subjNode; + /* Make sure subject entry has cert's key. */ + for (i=0; i<subjectEntry->ncerts; i++) { + if (SECITEM_ItemsAreEqual(&certKey, + &subjectEntry->certKeys[i])) { + /* Found matching cert key. */ + smap = (certDBSubjectEntryMap *)subjNode->appData; + smap->pCerts[i] = certNode; + break; + } + } + } + } + } + PORT_FreeArena(tmparena, PR_FALSE); + return SECSuccess; +} + +SECStatus +mapSubjectEntries(certDBArray *dbArray) +{ + certDBEntrySubject *subjectEntry; + certDBEntryNickname *nicknameEntry; + certDBEntrySMime *smimeEntry; + certDBEntryListNode *subjNode, *nickNode, *smimeNode; + certDBSubjectEntryMap *subjMap; + certDBEntryMap *nickMap, *smimeMap; + PRCList *sElem, *nElem, *mElem; + + for (sElem = PR_LIST_HEAD(&dbArray->subjects.link); + sElem != &dbArray->subjects.link; sElem = PR_NEXT_LINK(sElem)) { + /* Iterate over subject entries and map subjects to nickname + * and smime entries. The cert<->subject map will be handled + * by a subsequent call to mapCertEntries. + */ + subjNode = LISTNODE_CAST(sElem); + subjectEntry = (certDBEntrySubject *)&subjNode->entry; + subjMap = (certDBSubjectEntryMap *)subjNode->appData; + /* need to alloc memory here for array of matching certs. */ + subjMap->pCerts = PORT_ArenaAlloc(subjMap->arena, + subjectEntry->ncerts*sizeof(int)); + subjMap->numCerts = subjectEntry->ncerts; + if (subjectEntry->nickname) { + /* Subject should have a nickname entry, so create a link. */ + for (nElem = PR_LIST_HEAD(&dbArray->nicknames.link); + nElem != &dbArray->nicknames.link; + nElem = PR_NEXT_LINK(nElem)) { + /* Look for subject's nickname in nickname entries. */ + nickNode = LISTNODE_CAST(nElem); + nicknameEntry = (certDBEntryNickname *)&nickNode->entry; + nickMap = (certDBEntryMap *)nickNode->appData; + if (PL_strcmp(subjectEntry->nickname, + nicknameEntry->nickname) == 0) { + /* Found a nickname entry for subject's nickname. */ + if (SECITEM_ItemsAreEqual(&subjectEntry->derSubject, + &nicknameEntry->subjectName)) { + /* Nickname and subject match. */ + subjMap->pNickname = nickNode; + nickMap->pSubject = subjNode; + } else { + /* Nickname entry found is for diff. subject. */ + subjMap->pNickname = WrongEntry; + } + } + } + } else { + subjMap->pNickname = NoNickname; + } + if (subjectEntry->emailAddr) { + /* Subject should have an smime entry, so create a link. */ + for (mElem = PR_LIST_HEAD(&dbArray->smime.link); + mElem != &dbArray->smime.link; mElem = PR_NEXT_LINK(mElem)) { + /* Look for subject's email in S/MIME entries. */ + smimeNode = LISTNODE_CAST(mElem); + smimeEntry = (certDBEntrySMime *)&smimeNode->entry; + smimeMap = (certDBEntryMap *)smimeNode->appData; + if (PL_strcmp(subjectEntry->emailAddr, + smimeEntry->emailAddr) == 0) { + /* Found a S/MIME entry for subject's email. */ + if (SECITEM_ItemsAreEqual(&subjectEntry->derSubject, + &smimeEntry->subjectName)) { + /* S/MIME entry and subject match. */ + subjMap->pSMime = smimeNode; + smimeMap->pSubject = subjNode; + } else { + /* S/MIME entry found is for diff. subject. */ + subjMap->pSMime = WrongEntry; + } + } + } + } else { + subjMap->pSMime = NoSMime; + } + } + return SECSuccess; +} + +void +printnode(dbDebugInfo *info, const char *str, int num) +{ + if (!info->dograph) + return; + if (num < 0) { + PR_fprintf(info->graphfile, str); + } else { + PR_fprintf(info->graphfile, str, num); + } +} + +PRBool +map_handle_is_ok(dbDebugInfo *info, void *mapPtr, int indent) +{ + if (mapPtr == NULL) { + if (indent > 0) + printnode(info, " ", -1); + if (indent >= 0) + printnode(info, "******************* ", -1); + return PR_FALSE; + } else if (mapPtr == WrongEntry) { + if (indent > 0) + printnode(info, " ", -1); + if (indent >= 0) + printnode(info, "??????????????????? ", -1); + return PR_FALSE; + } else { + return PR_TRUE; + } +} + +/* these call each other */ +void print_smime_graph(dbDebugInfo *info, certDBEntryMap *smimeMap, + int direction); +void print_nickname_graph(dbDebugInfo *info, certDBEntryMap *nickMap, + int direction); +void print_subject_graph(dbDebugInfo *info, certDBSubjectEntryMap *subjMap, + int direction, int optindex, int opttype); +void print_cert_graph(dbDebugInfo *info, certDBEntryMap *certMap, + int direction); + +/* Given an smime entry, print its unique identifier. If GOLEFT is + * specified, print the cert<-subject<-smime map, else just print + * the smime entry. + */ +void +print_smime_graph(dbDebugInfo *info, certDBEntryMap *smimeMap, int direction) +{ + certDBSubjectEntryMap *subjMap; + certDBEntryListNode *subjNode; + if (direction == GOLEFT) { + /* Need to output subject and cert first, see print_subject_graph */ + subjNode = smimeMap->pSubject; + if (map_handle_is_ok(info, (void *)subjNode, 1)) { + subjMap = (certDBSubjectEntryMap *)subjNode->appData; + print_subject_graph(info, subjMap, GOLEFT, + smimeMap->index, certDBEntryTypeSMimeProfile); + } else { + printnode(info, "<---- S/MIME %5d ", smimeMap->index); + } + } else { + printnode(info, "S/MIME %5d ", smimeMap->index); + } +} + +/* Given a nickname entry, print its unique identifier. If GOLEFT is + * specified, print the cert<-subject<-nickname map, else just print + * the nickname entry. + */ +void +print_nickname_graph(dbDebugInfo *info, certDBEntryMap *nickMap, int direction) +{ + certDBSubjectEntryMap *subjMap; + certDBEntryListNode *subjNode; + if (direction == GOLEFT) { + /* Need to output subject and cert first, see print_subject_graph */ + subjNode = nickMap->pSubject; + if (map_handle_is_ok(info, (void *)subjNode, 1)) { + subjMap = (certDBSubjectEntryMap *)subjNode->appData; + print_subject_graph(info, subjMap, GOLEFT, + nickMap->index, certDBEntryTypeNickname); + } else { + printnode(info, "<---- Nickname %5d ", nickMap->index); + } + } else { + printnode(info, "Nickname %5d ", nickMap->index); + } +} + +/* Given a subject entry, if going right print the graph of the nickname|smime + * that it maps to (by its unique identifier); and if going left + * print the list of certs that it points to. + */ +void +print_subject_graph(dbDebugInfo *info, certDBSubjectEntryMap *subjMap, + int direction, int optindex, int opttype) +{ + certDBEntryMap *map; + certDBEntryListNode *node; + int i; + /* The first line of output always contains the cert id, subject id, + * and nickname|smime id. Subsequent lines may contain additional + * cert id's for the subject if going left or both directions. + * Ex. of printing the graph for a subject entry: + * Cert 3 <- Subject 5 -> Nickname 32 + * Cert 8 / + * Cert 9 / + * means subject 5 has 3 certs, 3, 8, and 9, and corresponds + * to nickname entry 32. + * To accomplish the above, it is required to dump the entire first + * line left-to-right, regardless of the input direction, and then + * finish up any remaining cert entries. Hence the code is uglier + * than one may expect. + */ + if (direction == GOLEFT || direction == GOBOTH) { + /* In this case, nothing should be output until the first cert is + * located and output (cert 3 in the above example). + */ + if (subjMap->numCerts == 0 || subjMap->pCerts == NULL) + /* XXX uh-oh */ + return; + /* get the first cert and dump it. */ + node = subjMap->pCerts[0]; + if (map_handle_is_ok(info, (void *)node, 0)) { + map = (certDBEntryMap *)node->appData; + /* going left here stops. */ + print_cert_graph(info, map, GOLEFT); + } + /* Now it is safe to output the subject id. */ + if (direction == GOLEFT) + printnode(info, "Subject %5d <---- ", subjMap->index); + else /* direction == GOBOTH */ + printnode(info, "Subject %5d ----> ", subjMap->index); + } + if (direction == GORIGHT || direction == GOBOTH) { + /* Okay, now output the nickname|smime for this subject. */ + if (direction != GOBOTH) /* handled above */ + printnode(info, "Subject %5d ----> ", subjMap->index); + if (subjMap->pNickname) { + node = subjMap->pNickname; + if (map_handle_is_ok(info, (void *)node, 0)) { + map = (certDBEntryMap *)node->appData; + /* going right here stops. */ + print_nickname_graph(info, map, GORIGHT); + } + } + if (subjMap->pSMime) { + node = subjMap->pSMime; + if (map_handle_is_ok(info, (void *)node, 0)) { + map = (certDBEntryMap *)node->appData; + /* going right here stops. */ + print_smime_graph(info, map, GORIGHT); + } + } + if (!subjMap->pNickname && !subjMap->pSMime) { + printnode(info, "******************* ", -1); + } + } + if (direction != GORIGHT) { /* going right has only one cert */ + if (opttype == certDBEntryTypeNickname) + printnode(info, "Nickname %5d ", optindex); + else if (opttype == certDBEntryTypeSMimeProfile) + printnode(info, "S/MIME %5d ", optindex); + for (i=1 /* 1st one already done */; i<subjMap->numCerts; i++) { + printnode(info, "\n", -1); /* start a new line */ + node = subjMap->pCerts[i]; + if (map_handle_is_ok(info, (void *)node, 0)) { + map = (certDBEntryMap *)node->appData; + /* going left here stops. */ + print_cert_graph(info, map, GOLEFT); + printnode(info, "/", -1); + } + } + } +} + +/* Given a cert entry, print its unique identifer. If GORIGHT is specified, + * print the cert->subject->nickname|smime map, else just print + * the cert entry. + */ +void +print_cert_graph(dbDebugInfo *info, certDBEntryMap *certMap, int direction) +{ + certDBSubjectEntryMap *subjMap; + certDBEntryListNode *subjNode; + if (direction == GOLEFT) { + printnode(info, "Cert %5d <---- ", certMap->index); + /* only want cert entry, terminate here. */ + return; + } + /* Keep going right then. */ + printnode(info, "Cert %5d ----> ", certMap->index); + subjNode = certMap->pSubject; + if (map_handle_is_ok(info, (void *)subjNode, 0)) { + subjMap = (certDBSubjectEntryMap *)subjNode->appData; + print_subject_graph(info, subjMap, GORIGHT, -1, -1); + } +} + +SECStatus +computeDBGraph(certDBArray *dbArray, dbDebugInfo *info) +{ + PRCList *cElem, *sElem, *nElem, *mElem; + certDBEntryListNode *node; + certDBEntryMap *map; + certDBSubjectEntryMap *subjMap; + + /* Graph is of this form: + * + * certs: + * cert ---> subject ---> (nickname|smime) + * + * subjects: + * cert <--- subject ---> (nickname|smime) + * + * nicknames and smime: + * cert <--- subject <--- (nickname|smime) + */ + + /* Print cert graph. */ + for (cElem = PR_LIST_HEAD(&dbArray->certs.link); + cElem != &dbArray->certs.link; cElem = PR_NEXT_LINK(cElem)) { + /* Print graph of everything to right of cert entry. */ + node = LISTNODE_CAST(cElem); + map = (certDBEntryMap *)node->appData; + print_cert_graph(info, map, GORIGHT); + printnode(info, "\n", -1); + } + printnode(info, "\n", -1); + + /* Print subject graph. */ + for (sElem = PR_LIST_HEAD(&dbArray->subjects.link); + sElem != &dbArray->subjects.link; sElem = PR_NEXT_LINK(sElem)) { + /* Print graph of everything to both sides of subject entry. */ + node = LISTNODE_CAST(sElem); + subjMap = (certDBSubjectEntryMap *)node->appData; + print_subject_graph(info, subjMap, GOBOTH, -1, -1); + printnode(info, "\n", -1); + } + printnode(info, "\n", -1); + + /* Print nickname graph. */ + for (nElem = PR_LIST_HEAD(&dbArray->nicknames.link); + nElem != &dbArray->nicknames.link; nElem = PR_NEXT_LINK(nElem)) { + /* Print graph of everything to left of nickname entry. */ + node = LISTNODE_CAST(nElem); + map = (certDBEntryMap *)node->appData; + print_nickname_graph(info, map, GOLEFT); + printnode(info, "\n", -1); + } + printnode(info, "\n", -1); + + /* Print smime graph. */ + for (mElem = PR_LIST_HEAD(&dbArray->smime.link); + mElem != &dbArray->smime.link; mElem = PR_NEXT_LINK(mElem)) { + /* Print graph of everything to left of smime entry. */ + node = LISTNODE_CAST(mElem); + if (node == NULL) break; + map = (certDBEntryMap *)node->appData; + print_smime_graph(info, map, GOLEFT); + printnode(info, "\n", -1); + } + printnode(info, "\n", -1); + + return SECSuccess; +} + +/* + * List the entries in the db, showing handles between entry types. + */ +void +verboseOutput(certDBArray *dbArray, dbDebugInfo *info) +{ + int i, ref; + PRCList *elem; + certDBEntryListNode *node; + certDBEntryMap *map; + certDBSubjectEntryMap *smap; + certDBEntrySubject *subjectEntry; + + /* List certs */ + for (elem = PR_LIST_HEAD(&dbArray->certs.link); + elem != &dbArray->certs.link; elem = PR_NEXT_LINK(elem)) { + node = LISTNODE_CAST(elem); + map = (certDBEntryMap *)node->appData; + dumpCertEntry((certDBEntryCert*)&node->entry, map->index, info->out); + /* walk the cert handle to it's subject entry */ + if (map_handle_is_ok(info, map->pSubject, -1)) { + smap = (certDBSubjectEntryMap *)map->pSubject->appData; + ref = smap->index; + PR_fprintf(info->out, "-->(subject %d)\n\n\n", ref); + } else { + PR_fprintf(info->out, "-->(MISSING SUBJECT ENTRY)\n\n\n"); + } + } + /* List subjects */ + for (elem = PR_LIST_HEAD(&dbArray->subjects.link); + elem != &dbArray->subjects.link; elem = PR_NEXT_LINK(elem)) { + node = LISTNODE_CAST(elem); + subjectEntry = (certDBEntrySubject *)&node->entry; + smap = (certDBSubjectEntryMap *)node->appData; + dumpSubjectEntry(subjectEntry, smap->index, info->out); + /* iterate over subject's certs */ + for (i=0; i<smap->numCerts; i++) { + /* walk each subject handle to it's cert entries */ + if (map_handle_is_ok(info, smap->pCerts[i], -1)) { + ref = ((certDBEntryMap *)smap->pCerts[i]->appData)->index; + PR_fprintf(info->out, "-->(%d. certificate %d)\n", i, ref); + } else { + PR_fprintf(info->out, "-->(%d. MISSING CERT ENTRY)\n", i); + } + } + if (subjectEntry->nickname) { + /* walk each subject handle to it's nickname entry */ + if (map_handle_is_ok(info, smap->pNickname, -1)) { + ref = ((certDBEntryMap *)smap->pNickname->appData)->index; + PR_fprintf(info->out, "-->(nickname %d)\n", ref); + } else { + PR_fprintf(info->out, "-->(MISSING NICKNAME ENTRY)\n"); + } + } + if (subjectEntry->emailAddr) { + /* walk each subject handle to it's smime entry */ + if (map_handle_is_ok(info, smap->pSMime, -1)) { + ref = ((certDBEntryMap *)smap->pSMime->appData)->index; + PR_fprintf(info->out, "-->(s/mime %d)\n", ref); + } else { + PR_fprintf(info->out, "-->(MISSING S/MIME ENTRY)\n"); + } + } + PR_fprintf(info->out, "\n\n"); + } + for (elem = PR_LIST_HEAD(&dbArray->nicknames.link); + elem != &dbArray->nicknames.link; elem = PR_NEXT_LINK(elem)) { + node = LISTNODE_CAST(elem); + map = (certDBEntryMap *)node->appData; + dumpNicknameEntry((certDBEntryNickname*)&node->entry, map->index, + info->out); + if (map_handle_is_ok(info, map->pSubject, -1)) { + ref = ((certDBEntryMap *)map->pSubject->appData)->index; + PR_fprintf(info->out, "-->(subject %d)\n\n\n", ref); + } else { + PR_fprintf(info->out, "-->(MISSING SUBJECT ENTRY)\n\n\n"); + } + } + for (elem = PR_LIST_HEAD(&dbArray->smime.link); + elem != &dbArray->smime.link; elem = PR_NEXT_LINK(elem)) { + node = LISTNODE_CAST(elem); + map = (certDBEntryMap *)node->appData; + dumpSMimeEntry((certDBEntrySMime*)&node->entry, map->index, info->out); + if (map_handle_is_ok(info, map->pSubject, -1)) { + ref = ((certDBEntryMap *)map->pSubject->appData)->index; + PR_fprintf(info->out, "-->(subject %d)\n\n\n", ref); + } else { + PR_fprintf(info->out, "-->(MISSING SUBJECT ENTRY)\n\n\n"); + } + } + PR_fprintf(info->out, "\n\n"); +} + +char *errResult[] = { + "Certificate entries that had no subject entry.", + "Certificate entries that had no key in their subject entry.", + "Subject entries that had no nickname or email address.", + "Redundant nicknames (subjects with the same nickname).", + "Subject entries that had no nickname entry.", + "Redundant email addresses (subjects with the same email address).", + "Subject entries that had no S/MIME entry.", + "Nickname entries that had no subject entry.", + "S/MIME entries that had no subject entry.", +}; + +int +fillDBEntryArray(CERTCertDBHandle *handle, certDBEntryType type, + certDBEntryListNode *list) +{ + PRCList *elem; + certDBEntryListNode *node; + certDBEntryMap *mnode; + certDBSubjectEntryMap *smnode; + PRArenaPool *arena; + int count = 0; + /* Initialize a dummy entry in the list. The list head will be the + * next element, so this element is skipped by for loops. + */ + PR_INIT_CLIST((PRCList *)list); + /* Collect all of the cert db entries for this type into a list. */ + SEC_TraverseDBEntries(handle, type, SEC_GetCertDBEntryList, + (PRCList *)list); + for (elem = PR_LIST_HEAD(&list->link); + elem != &list->link; elem = PR_NEXT_LINK(elem)) { + /* Iterate over the entries and ... */ + node = (certDBEntryListNode *)elem; + if (type != certDBEntryTypeSubject) { + arena = PORT_NewArena(sizeof(*mnode)); + mnode = (certDBEntryMap *)PORT_ArenaZAlloc(arena, sizeof(*mnode)); + mnode->arena = arena; + /* ... assign a unique index number to each node, and ... */ + mnode->index = count; + /* ... set the map pointer for the node. */ + node->appData = (void *)mnode; + } else { + /* allocate some room for the cert pointers also */ + arena = PORT_NewArena(sizeof(*smnode) + 20*sizeof(void *)); + smnode = (certDBSubjectEntryMap *) + PORT_ArenaZAlloc(arena, sizeof(*smnode)); + smnode->arena = arena; + smnode->index = count; + node->appData = (void *)smnode; + } + count++; + } + return count; +} + +void +freeDBEntryList(PRCList *list) +{ + PRCList *next, *elem; + certDBEntryListNode *node; + certDBEntryMap *map; + + for (elem = PR_LIST_HEAD(list); elem != list;) { + next = PR_NEXT_LINK(elem); + node = (certDBEntryListNode *)elem; + map = (certDBEntryMap *)node->appData; + PR_REMOVE_LINK(&node->link); + PORT_FreeArena(map->arena, PR_TRUE); + PORT_FreeArena(node->entry.common.arena, PR_TRUE); + elem = next; + } +} + +void +DBCK_DebugDB(CERTCertDBHandle *handle, PRFileDesc *out, PRFileDesc *mailfile) +{ + int i, nCertsFound, nSubjFound, nErr; + int nCerts, nSubjects, nSubjCerts, nNicknames, nSMime; + PRCList *elem; + char c; + dbDebugInfo info; + certDBArray dbArray; + + PORT_Memset(&dbArray, 0, sizeof(dbArray)); + PORT_Memset(&info, 0, sizeof(info)); + info.verbose = (out == NULL) ? PR_FALSE : PR_TRUE ; + info.dograph = (mailfile == NULL) ? PR_FALSE : PR_TRUE ; + info.out = (out) ? out : PR_STDOUT; + info.graphfile = mailfile; + + /* Fill the array structure with cert/subject/nickname/smime entries. */ + dbArray.numCerts = fillDBEntryArray(handle, certDBEntryTypeCert, + &dbArray.certs); + dbArray.numSubjects = fillDBEntryArray(handle, certDBEntryTypeSubject, + &dbArray.subjects); + dbArray.numNicknames = fillDBEntryArray(handle, certDBEntryTypeNickname, + &dbArray.nicknames); + dbArray.numSMime = fillDBEntryArray(handle, certDBEntryTypeSMimeProfile, + &dbArray.smime); + + /* Compute the map between the database entries. */ + mapSubjectEntries(&dbArray); + mapCertEntries(&dbArray); + computeDBGraph(&dbArray, &info); + + /* Store the totals for later reference. */ + nCerts = dbArray.numCerts; + nSubjects = dbArray.numSubjects; + nNicknames = dbArray.numNicknames; + nSMime = dbArray.numSMime; + nSubjCerts = 0; + for (elem = PR_LIST_HEAD(&dbArray.subjects.link); + elem != &dbArray.subjects.link; elem = PR_NEXT_LINK(elem)) { + certDBSubjectEntryMap *smap; + smap = (certDBSubjectEntryMap *)LISTNODE_CAST(elem)->appData; + nSubjCerts += smap->numCerts; + } + + if (info.verbose) { + /* Dump the database contents. */ + verboseOutput(&dbArray, &info); + } + + freeDBEntryList(&dbArray.certs.link); + freeDBEntryList(&dbArray.subjects.link); + freeDBEntryList(&dbArray.nicknames.link); + freeDBEntryList(&dbArray.smime.link); + + PR_fprintf(info.out, "\n"); + PR_fprintf(info.out, "Database statistics:\n"); + PR_fprintf(info.out, "N0: Found %4d Certificate entries.\n", + nCerts); + PR_fprintf(info.out, "N1: Found %4d Subject entries (unique DN's).\n", + nSubjects); + PR_fprintf(info.out, "N2: Found %4d Cert keys within Subject entries.\n", + nSubjCerts); + PR_fprintf(info.out, "N3: Found %4d Nickname entries.\n", + nNicknames); + PR_fprintf(info.out, "N4: Found %4d S/MIME entries.\n", + nSMime); + PR_fprintf(info.out, "\n"); + + nErr = 0; + for (i=0; i<sizeof(errResult)/sizeof(char*); i++) { + PR_fprintf(info.out, "E%d: Found %4d %s\n", + i, info.dbErrors[i], errResult[i]); + nErr += info.dbErrors[i]; + } + PR_fprintf(info.out, "--------------\n Found %4d errors in database.\n", + nErr); + + PR_fprintf(info.out, "\nCertificates:\n"); + PR_fprintf(info.out, "N0 == N2 + E%d + E%d\n", NoSubjectForCert, + SubjectHasNoKeyForCert); + nCertsFound = nSubjCerts + + info.dbErrors[NoSubjectForCert] + + info.dbErrors[SubjectHasNoKeyForCert]; + c = (nCertsFound == nCerts) ? '=' : '!'; + PR_fprintf(info.out, "%d %c= %d + %d + %d\n", nCerts, c, nSubjCerts, + info.dbErrors[NoSubjectForCert], + info.dbErrors[SubjectHasNoKeyForCert]); + PR_fprintf(info.out, "\nSubjects:\n"); + PR_fprintf(info.out, "N1 == N3 + N4 + E%d + E%d + E%d + E%d + E%d - E%d - E%d\n", + NoNicknameOrSMimeForSubject, WrongNicknameForSubject, + NoNicknameEntry, WrongSMimeForSubject, NoSMimeEntry, + NoSubjectForNickname, NoSubjectForSMime); + PR_fprintf(info.out, " - #(subjects with both nickname and S/MIME entries)\n"); + nSubjFound = nNicknames + nSMime + + info.dbErrors[NoNicknameOrSMimeForSubject] + + info.dbErrors[WrongNicknameForSubject] + + info.dbErrors[NoNicknameEntry] + + info.dbErrors[WrongSMimeForSubject] + + info.dbErrors[NoSMimeEntry] - + info.dbErrors[NoSubjectForNickname] - + info.dbErrors[NoSubjectForSMime] - + info.dbErrors[NicknameAndSMimeEntry]; + c = (nSubjFound == nSubjects) ? '=' : '!'; + PR_fprintf(info.out, "%d %c= %d + %d + %d + %d + %d + %d + %d - %d - %d - %d\n", + nSubjects, c, nNicknames, nSMime, + info.dbErrors[NoNicknameOrSMimeForSubject], + info.dbErrors[WrongNicknameForSubject], + info.dbErrors[NoNicknameEntry], + info.dbErrors[WrongSMimeForSubject], + info.dbErrors[NoSMimeEntry], + info.dbErrors[NoSubjectForNickname], + info.dbErrors[NoSubjectForSMime], + info.dbErrors[NicknameAndSMimeEntry]); + PR_fprintf(info.out, "\n"); +} + +#ifdef DORECOVER +enum { + dbInvalidCert = 0, + dbNoSMimeProfile, + dbOlderCert, + dbBadCertificate, + dbCertNotWrittenToDB +}; + +typedef struct dbRestoreInfoStr +{ + CERTCertDBHandle *handle; + PRBool verbose; + PRFileDesc *out; + int nCerts; + int nOldCerts; + int dbErrors[5]; + PRBool removeType[3]; + PRBool promptUser[3]; +} dbRestoreInfo; + +char * +IsEmailCert(CERTCertificate *cert) +{ + char *email, *tmp1, *tmp2; + PRBool isCA; + int len; + + if (!cert->subjectName) { + return NULL; + } + + tmp1 = PORT_Strstr(cert->subjectName, "E="); + tmp2 = PORT_Strstr(cert->subjectName, "MAIL="); + /* XXX Nelson has cert for KTrilli which does not have either + * of above but is email cert (has cert->emailAddr). + */ + if (!tmp1 && !tmp2 && !cert->emailAddr) { + return NULL; + } + + /* Server or CA cert, not personal email. */ + isCA = CERT_IsCACert(cert, NULL); + if (isCA) + return NULL; + + /* XXX CERT_IsCACert advertises checking the key usage ext., + but doesn't appear to. */ + /* Check the key usage extension. */ + if (cert->keyUsagePresent) { + /* Must at least be able to sign or encrypt (not neccesarily + * both if it is one of a dual cert). + */ + if (!((cert->rawKeyUsage & KU_DIGITAL_SIGNATURE) || + (cert->rawKeyUsage & KU_KEY_ENCIPHERMENT))) + return NULL; + + /* CA cert, not personal email. */ + if (cert->rawKeyUsage & (KU_KEY_CERT_SIGN | KU_CRL_SIGN)) + return NULL; + } + + if (cert->emailAddr) { + email = PORT_Strdup(cert->emailAddr); + } else { + if (tmp1) + tmp1 += 2; /* "E=" */ + else + tmp1 = tmp2 + 5; /* "MAIL=" */ + len = strcspn(tmp1, ", "); + email = (char*)PORT_Alloc(len+1); + PORT_Strncpy(email, tmp1, len); + email[len] = '\0'; + } + + return email; +} + +SECStatus +deleteit(CERTCertificate *cert, void *arg) +{ + return SEC_DeletePermCertificate(cert); +} + +/* Different than DeleteCertificate - has the added bonus of removing + * all certs with the same DN. + */ +SECStatus +deleteAllEntriesForCert(CERTCertDBHandle *handle, CERTCertificate *cert, + PRFileDesc *outfile) +{ +#if 0 + certDBEntrySubject *subjectEntry; + certDBEntryNickname *nicknameEntry; + certDBEntrySMime *smimeEntry; + int i; +#endif + + if (outfile) { + PR_fprintf(outfile, "$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$\n\n"); + PR_fprintf(outfile, "Deleting redundant certificate:\n"); + dumpCertificate(cert, -1, outfile); + } + + CERT_TraverseCertsForSubject(handle, cert->subjectList, deleteit, NULL); +#if 0 + CERT_LockDB(handle); + subjectEntry = ReadDBSubjectEntry(handle, &cert->derSubject); + /* It had better be there, or created a bad db. */ + PORT_Assert(subjectEntry); + for (i=0; i<subjectEntry->ncerts; i++) { + DeleteDBCertEntry(handle, &subjectEntry->certKeys[i]); + } + DeleteDBSubjectEntry(handle, &cert->derSubject); + if (subjectEntry->emailAddr) { + smimeEntry = ReadDBSMimeEntry(handle, subjectEntry->emailAddr); + if (smimeEntry) { + if (SECITEM_ItemsAreEqual(&subjectEntry->derSubject, + &smimeEntry->subjectName)) + /* Only delete it if it's for this subject! */ + DeleteDBSMimeEntry(handle, subjectEntry->emailAddr); + SEC_DestroyDBEntry((certDBEntry*)smimeEntry); + } + } + if (subjectEntry->nickname) { + nicknameEntry = ReadDBNicknameEntry(handle, subjectEntry->nickname); + if (nicknameEntry) { + if (SECITEM_ItemsAreEqual(&subjectEntry->derSubject, + &nicknameEntry->subjectName)) + /* Only delete it if it's for this subject! */ + DeleteDBNicknameEntry(handle, subjectEntry->nickname); + SEC_DestroyDBEntry((certDBEntry*)nicknameEntry); + } + } + SEC_DestroyDBEntry((certDBEntry*)subjectEntry); + CERT_UnlockDB(handle); +#endif + return SECSuccess; +} + +void +getCertsToDelete(char *numlist, int len, int *certNums, int nCerts) +{ + int j, num; + char *numstr, *numend, *end; + + numstr = numlist; + end = numstr + len - 1; + while (numstr != end) { + numend = strpbrk(numstr, ", \n"); + *numend = '\0'; + if (PORT_Strlen(numstr) == 0) + return; + num = PORT_Atoi(numstr); + if (numstr == numlist) + certNums[0] = num; + for (j=1; j<nCerts+1; j++) { + if (num == certNums[j]) { + certNums[j] = -1; + break; + } + } + if (numend == end) + break; + numstr = strpbrk(numend+1, "0123456789"); + } +} + +PRBool +userSaysDeleteCert(CERTCertificate **certs, int nCerts, + int errtype, dbRestoreInfo *info, int *certNums) +{ + char response[32]; + int32 nb; + int i; + /* User wants to remove cert without prompting. */ + if (info->promptUser[errtype] == PR_FALSE) + return (info->removeType[errtype]); + switch (errtype) { + case dbInvalidCert: + PR_fprintf(PR_STDOUT, "******** Expired ********\n"); + PR_fprintf(PR_STDOUT, "Cert has expired.\n\n"); + dumpCertificate(certs[0], -1, PR_STDOUT); + PR_fprintf(PR_STDOUT, + "Keep it? (y/n - this one, Y/N - all expired certs) [n] "); + break; + case dbNoSMimeProfile: + PR_fprintf(PR_STDOUT, "******** No Profile ********\n"); + PR_fprintf(PR_STDOUT, "S/MIME cert has no profile.\n\n"); + dumpCertificate(certs[0], -1, PR_STDOUT); + PR_fprintf(PR_STDOUT, + "Keep it? (y/n - this one, Y/N - all S/MIME w/o profile) [n] "); + break; + case dbOlderCert: + PR_fprintf(PR_STDOUT, "******* Redundant nickname/email *******\n\n"); + PR_fprintf(PR_STDOUT, "These certs have the same nickname/email:\n"); + for (i=0; i<nCerts; i++) + dumpCertificate(certs[i], i, PR_STDOUT); + PR_fprintf(PR_STDOUT, + "Enter the certs you would like to keep from those listed above.\n"); + PR_fprintf(PR_STDOUT, + "Use a comma-separated list of the cert numbers (ex. 0, 8, 12).\n"); + PR_fprintf(PR_STDOUT, + "The first cert in the list will be the primary cert\n"); + PR_fprintf(PR_STDOUT, + " accessed by the nickname/email handle.\n"); + PR_fprintf(PR_STDOUT, + "List cert numbers to keep here, or hit enter\n"); + PR_fprintf(PR_STDOUT, + " to always keep only the newest cert: "); + break; + default: + } + nb = PR_Read(PR_STDIN, response, sizeof(response)); + PR_fprintf(PR_STDOUT, "\n\n"); + if (errtype == dbOlderCert) { + if (!isdigit(response[0])) { + info->promptUser[errtype] = PR_FALSE; + info->removeType[errtype] = PR_TRUE; + return PR_TRUE; + } + getCertsToDelete(response, nb, certNums, nCerts); + return PR_TRUE; + } + /* User doesn't want to be prompted for this type anymore. */ + if (response[0] == 'Y') { + info->promptUser[errtype] = PR_FALSE; + info->removeType[errtype] = PR_FALSE; + return PR_FALSE; + } else if (response[0] == 'N') { + info->promptUser[errtype] = PR_FALSE; + info->removeType[errtype] = PR_TRUE; + return PR_TRUE; + } + return (response[0] != 'y') ? PR_TRUE : PR_FALSE; +} + +SECStatus +addCertToDB(certDBEntryCert *certEntry, dbRestoreInfo *info, + CERTCertDBHandle *oldhandle) +{ + SECStatus rv = SECSuccess; + PRBool allowOverride; + PRBool userCert; + SECCertTimeValidity validity; + CERTCertificate *oldCert = NULL; + CERTCertificate *dbCert = NULL; + CERTCertificate *newCert = NULL; + CERTCertTrust *trust; + certDBEntrySMime *smimeEntry = NULL; + char *email = NULL; + char *nickname = NULL; + int nCertsForSubject = 1; + + oldCert = CERT_DecodeDERCertificate(&certEntry->derCert, PR_FALSE, + certEntry->nickname); + if (!oldCert) { + info->dbErrors[dbBadCertificate]++; + SEC_DestroyDBEntry((certDBEntry*)certEntry); + return SECSuccess; + } + + oldCert->dbEntry = certEntry; + oldCert->trust = &certEntry->trust; + oldCert->dbhandle = oldhandle; + + trust = oldCert->trust; + + info->nOldCerts++; + + if (info->verbose) + PR_fprintf(info->out, "%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%\n\n"); + + if (oldCert->nickname) + nickname = PORT_Strdup(oldCert->nickname); + + /* Always keep user certs. Skip ahead. */ + /* XXX if someone sends themselves a signed message, it is possible + for their cert to be imported as an "other" cert, not a user cert. + this mucks with smime entries... */ + userCert = (SEC_GET_TRUST_FLAGS(trust, trustSSL) & CERTDB_USER) || + (SEC_GET_TRUST_FLAGS(trust, trustEmail) & CERTDB_USER) || + (SEC_GET_TRUST_FLAGS(trust, trustObjectSigning) & CERTDB_USER); + if (userCert) + goto createcert; + + /* If user chooses so, ignore expired certificates. */ + allowOverride = (PRBool)((oldCert->keyUsage == certUsageSSLServer) || + (oldCert->keyUsage == certUsageSSLServerWithStepUp)); + validity = CERT_CheckCertValidTimes(oldCert, PR_Now(), allowOverride); + /* If cert expired and user wants to delete it, ignore it. */ + if ((validity != secCertTimeValid) && + userSaysDeleteCert(&oldCert, 1, dbInvalidCert, info, 0)) { + info->dbErrors[dbInvalidCert]++; + if (info->verbose) { + PR_fprintf(info->out, "Deleting expired certificate:\n"); + dumpCertificate(oldCert, -1, info->out); + } + goto cleanup; + } + + /* New database will already have default certs, don't attempt + to overwrite them. */ + dbCert = CERT_FindCertByDERCert(info->handle, &oldCert->derCert); + if (dbCert) { + info->nCerts++; + if (info->verbose) { + PR_fprintf(info->out, "Added certificate to database:\n"); + dumpCertificate(oldCert, -1, info->out); + } + goto cleanup; + } + + /* Determine if cert is S/MIME and get its email if so. */ + email = IsEmailCert(oldCert); + + /* + XXX Just create empty profiles? + if (email) { + SECItem *profile = CERT_FindSMimeProfile(oldCert); + if (!profile && + userSaysDeleteCert(&oldCert, 1, dbNoSMimeProfile, info, 0)) { + info->dbErrors[dbNoSMimeProfile]++; + if (info->verbose) { + PR_fprintf(info->out, + "Deleted cert missing S/MIME profile.\n"); + dumpCertificate(oldCert, -1, info->out); + } + goto cleanup; + } else { + SECITEM_FreeItem(profile); + } + } + */ + +createcert: + + /* Sometimes happens... */ + if (!nickname && userCert) + nickname = PORT_Strdup(oldCert->subjectName); + + /* Create a new certificate, copy of the old one. */ + newCert = CERT_NewTempCertificate(info->handle, &oldCert->derCert, + nickname, PR_FALSE, PR_TRUE); + if (!newCert) { + PR_fprintf(PR_STDERR, "Unable to create new certificate.\n"); + dumpCertificate(oldCert, -1, PR_STDERR); + info->dbErrors[dbBadCertificate]++; + goto cleanup; + } + + /* Add the cert to the new database. */ + rv = CERT_AddTempCertToPerm(newCert, nickname, oldCert->trust); + if (rv) { + PR_fprintf(PR_STDERR, "Failed to write temp cert to perm database.\n"); + dumpCertificate(oldCert, -1, PR_STDERR); + info->dbErrors[dbCertNotWrittenToDB]++; + goto cleanup; + } + + if (info->verbose) { + PR_fprintf(info->out, "Added certificate to database:\n"); + dumpCertificate(oldCert, -1, info->out); + } + + /* If the cert is an S/MIME cert, and the first with it's subject, + * modify the subject entry to include the email address, + * CERT_AddTempCertToPerm does not do email addresses and S/MIME entries. + */ + if (smimeEntry) { /*&& !userCert && nCertsForSubject == 1) { */ +#if 0 + UpdateSubjectWithEmailAddr(newCert, email); +#endif + SECItem emailProfile, profileTime; + rv = CERT_FindFullSMimeProfile(oldCert, &emailProfile, &profileTime); + /* calls UpdateSubjectWithEmailAddr */ + if (rv == SECSuccess) + rv = CERT_SaveSMimeProfile(newCert, &emailProfile, &profileTime); + } + + info->nCerts++; + +cleanup: + + if (nickname) + PORT_Free(nickname); + if (email) + PORT_Free(email); + if (oldCert) + CERT_DestroyCertificate(oldCert); + if (dbCert) + CERT_DestroyCertificate(dbCert); + if (newCert) + CERT_DestroyCertificate(newCert); + if (smimeEntry) + SEC_DestroyDBEntry((certDBEntry*)smimeEntry); + return SECSuccess; +} + +#if 0 +SECStatus +copyDBEntry(SECItem *data, SECItem *key, certDBEntryType type, void *pdata) +{ + SECStatus rv; + CERTCertDBHandle *newdb = (CERTCertDBHandle *)pdata; + certDBEntryCommon common; + SECItem dbkey; + + common.type = type; + common.version = CERT_DB_FILE_VERSION; + common.flags = data->data[2]; + common.arena = NULL; + + dbkey.len = key->len + SEC_DB_KEY_HEADER_LEN; + dbkey.data = (unsigned char *)PORT_Alloc(dbkey.len*sizeof(unsigned char)); + PORT_Memcpy(&dbkey.data[SEC_DB_KEY_HEADER_LEN], key->data, key->len); + dbkey.data[0] = type; + + rv = WriteDBEntry(newdb, &common, &dbkey, data); + + PORT_Free(dbkey.data); + return rv; +} +#endif + +int +certIsOlder(CERTCertificate **cert1, CERTCertificate** cert2) +{ + return !CERT_IsNewer(*cert1, *cert2); +} + +int +findNewestSubjectForEmail(CERTCertDBHandle *handle, int subjectNum, + certDBArray *dbArray, dbRestoreInfo *info, + int *subjectWithSMime, int *smimeForSubject) +{ + int newestSubject; + int subjectsForEmail[50]; + int i, j, ns, sNum; + certDBEntryListNode *subjects = &dbArray->subjects; + certDBEntryListNode *smime = &dbArray->smime; + certDBEntrySubject *subjectEntry1, *subjectEntry2; + certDBEntrySMime *smimeEntry; + CERTCertificate **certs; + CERTCertificate *cert; + CERTCertTrust *trust; + PRBool userCert; + int *certNums; + + ns = 0; + subjectEntry1 = (certDBEntrySubject*)&subjects.entries[subjectNum]; + subjectsForEmail[ns++] = subjectNum; + + *subjectWithSMime = -1; + *smimeForSubject = -1; + newestSubject = subjectNum; + + cert = CERT_FindCertByKey(handle, &subjectEntry1->certKeys[0]); + if (cert) { + trust = cert->trust; + userCert = (SEC_GET_TRUST_FLAGS(trust, trustSSL) & CERTDB_USER) || + (SEC_GET_TRUST_FLAGS(trust, trustEmail) & CERTDB_USER) || + (SEC_GET_TRUST_FLAGS(trust, trustObjectSigning) & CERTDB_USER); + CERT_DestroyCertificate(cert); + } + + /* Loop over the remaining subjects. */ + for (i=subjectNum+1; i<subjects.numEntries; i++) { + subjectEntry2 = (certDBEntrySubject*)&subjects.entries[i]; + if (!subjectEntry2) + continue; + if (subjectEntry2->emailAddr && + PORT_Strcmp(subjectEntry1->emailAddr, + subjectEntry2->emailAddr) == 0) { + /* Found a subject using the same email address. */ + subjectsForEmail[ns++] = i; + } + } + + /* Find the S/MIME entry for this email address. */ + for (i=0; i<smime.numEntries; i++) { + smimeEntry = (certDBEntrySMime*)&smime.entries[i]; + if (smimeEntry->common.arena == NULL) + continue; + if (PORT_Strcmp(subjectEntry1->emailAddr, smimeEntry->emailAddr) == 0) { + /* Find which of the subjects uses this S/MIME entry. */ + for (j=0; j<ns && *subjectWithSMime < 0; j++) { + sNum = subjectsForEmail[j]; + subjectEntry2 = (certDBEntrySubject*)&subjects.entries[sNum]; + if (SECITEM_ItemsAreEqual(&smimeEntry->subjectName, + &subjectEntry2->derSubject)) { + /* Found the subject corresponding to the S/MIME entry. */ + *subjectWithSMime = sNum; + *smimeForSubject = i; + } + } + SEC_DestroyDBEntry((certDBEntry*)smimeEntry); + PORT_Memset(smimeEntry, 0, sizeof(certDBEntry)); + break; + } + } + + if (ns <= 1) + return subjectNum; + + if (userCert) + return *subjectWithSMime; + + /* Now find which of the subjects has the newest cert. */ + certs = (CERTCertificate**)PORT_Alloc(ns*sizeof(CERTCertificate*)); + certNums = (int*)PORT_Alloc((ns+1)*sizeof(int)); + certNums[0] = 0; + for (i=0; i<ns; i++) { + sNum = subjectsForEmail[i]; + subjectEntry1 = (certDBEntrySubject*)&subjects.entries[sNum]; + certs[i] = CERT_FindCertByKey(handle, &subjectEntry1->certKeys[0]); + certNums[i+1] = i; + } + /* Sort the array by validity. */ + qsort(certs, ns, sizeof(CERTCertificate*), + (int (*)(const void *, const void *))certIsOlder); + newestSubject = -1; + for (i=0; i<ns; i++) { + sNum = subjectsForEmail[i]; + subjectEntry1 = (certDBEntrySubject*)&subjects.entries[sNum]; + if (SECITEM_ItemsAreEqual(&subjectEntry1->derSubject, + &certs[0]->derSubject)) + newestSubject = sNum; + else + SEC_DestroyDBEntry((certDBEntry*)subjectEntry1); + } + if (info && userSaysDeleteCert(certs, ns, dbOlderCert, info, certNums)) { + for (i=1; i<ns+1; i++) { + if (certNums[i] >= 0 && certNums[i] != certNums[0]) { + deleteAllEntriesForCert(handle, certs[certNums[i]], info->out); + info->dbErrors[dbOlderCert]++; + } + } + } + CERT_DestroyCertArray(certs, ns); + return newestSubject; +} + +CERTCertDBHandle * +DBCK_ReconstructDBFromCerts(CERTCertDBHandle *oldhandle, char *newdbname, + PRFileDesc *outfile, PRBool removeExpired, + PRBool requireProfile, PRBool singleEntry, + PRBool promptUser) +{ + SECStatus rv; + dbRestoreInfo info; + certDBEntryContentVersion *oldContentVersion; + certDBArray dbArray; + int i; + + PORT_Memset(&dbArray, 0, sizeof(dbArray)); + PORT_Memset(&info, 0, sizeof(info)); + info.verbose = (outfile) ? PR_TRUE : PR_FALSE; + info.out = (outfile) ? outfile : PR_STDOUT; + info.removeType[dbInvalidCert] = removeExpired; + info.removeType[dbNoSMimeProfile] = requireProfile; + info.removeType[dbOlderCert] = singleEntry; + info.promptUser[dbInvalidCert] = promptUser; + info.promptUser[dbNoSMimeProfile] = promptUser; + info.promptUser[dbOlderCert] = promptUser; + + /* Allocate a handle to fill with CERT_OpenCertDB below. */ + info.handle = (CERTCertDBHandle *)PORT_ZAlloc(sizeof(CERTCertDBHandle)); + if (!info.handle) { + fprintf(stderr, "unable to get database handle"); + return NULL; + } + + /* Create a certdb with the most recent set of roots. */ + rv = CERT_OpenCertDBFilename(info.handle, newdbname, PR_FALSE); + + if (rv) { + fprintf(stderr, "could not open certificate database"); + goto loser; + } + + /* Create certificate, subject, nickname, and email records. + * mcom_db seems to have a sequential access bug. Though reads and writes + * should be allowed during traversal, they seem to screw up the sequence. + * So, stuff all the cert entries into an array, and loop over the array + * doing read/writes in the db. + */ + fillDBEntryArray(oldhandle, certDBEntryTypeCert, &dbArray.certs); + for (elem = PR_LIST_HEAD(&dbArray->certs.link); + elem != &dbArray->certs.link; elem = PR_NEXT_LINK(elem)) { + node = LISTNODE_CAST(elem); + addCertToDB((certDBEntryCert*)&node->entry, &info, oldhandle); + /* entries get destroyed in addCertToDB */ + } +#if 0 + rv = SEC_TraverseDBEntries(oldhandle, certDBEntryTypeSMimeProfile, + copyDBEntry, info.handle); +#endif + + /* Fix up the pointers between (nickname|S/MIME) --> (subject). + * Create S/MIME entries for S/MIME certs. + * Have the S/MIME entry point to the last-expiring cert using + * an email address. + */ +#if 0 + CERT_RedoHandlesForSubjects(info.handle, singleEntry, &info); +#endif + + freeDBEntryList(&dbArray.certs.link); + + /* Copy over the version record. */ + /* XXX Already exists - and _must_ be correct... */ + /* + versionEntry = ReadDBVersionEntry(oldhandle); + rv = WriteDBVersionEntry(info.handle, versionEntry); + */ + + /* Copy over the content version record. */ + /* XXX Can probably get useful info from old content version? + * Was this db created before/after this tool? etc. + */ +#if 0 + oldContentVersion = ReadDBContentVersionEntry(oldhandle); + CERT_SetDBContentVersion(oldContentVersion->contentVersion, info.handle); +#endif + +#if 0 + /* Copy over the CRL & KRL records. */ + rv = SEC_TraverseDBEntries(oldhandle, certDBEntryTypeRevocation, + copyDBEntry, info.handle); + /* XXX Only one KRL, just do db->get? */ + rv = SEC_TraverseDBEntries(oldhandle, certDBEntryTypeKeyRevocation, + copyDBEntry, info.handle); +#endif + + PR_fprintf(info.out, "Database had %d certificates.\n", info.nOldCerts); + + PR_fprintf(info.out, "Reconstructed %d certificates.\n", info.nCerts); + PR_fprintf(info.out, "(ax) Rejected %d expired certificates.\n", + info.dbErrors[dbInvalidCert]); + PR_fprintf(info.out, "(as) Rejected %d S/MIME certificates missing a profile.\n", + info.dbErrors[dbNoSMimeProfile]); + PR_fprintf(info.out, "(ar) Rejected %d certificates for which a newer certificate was found.\n", + info.dbErrors[dbOlderCert]); + PR_fprintf(info.out, " Rejected %d corrupt certificates.\n", + info.dbErrors[dbBadCertificate]); + PR_fprintf(info.out, " Rejected %d certificates which did not write to the DB.\n", + info.dbErrors[dbCertNotWrittenToDB]); + + if (rv) + goto loser; + + return info.handle; + +loser: + if (info.handle) + PORT_Free(info.handle); + return NULL; +} +#endif /* DORECOVER */ + +enum { + cmd_Debug = 0, + cmd_LongUsage, + cmd_Recover +}; + +enum { + opt_KeepAll = 0, + opt_CertDir, + opt_Dumpfile, + opt_InputDB, + opt_OutputDB, + opt_Mailfile, + opt_Prompt, + opt_KeepRedundant, + opt_KeepNoSMimeProfile, + opt_Verbose, + opt_KeepExpired +}; + +static secuCommandFlag dbck_commands[] = +{ + { /* cmd_Debug, */ 'D', PR_FALSE, 0, PR_FALSE }, + { /* cmd_LongUsage,*/ 'H', PR_FALSE, 0, PR_FALSE }, + { /* cmd_Recover, */ 'R', PR_FALSE, 0, PR_FALSE } +}; + +static secuCommandFlag dbck_options[] = +{ + { /* opt_KeepAll, */ 'a', PR_FALSE, 0, PR_FALSE }, + { /* opt_CertDir, */ 'd', PR_TRUE, 0, PR_FALSE }, + { /* opt_Dumpfile, */ 'f', PR_TRUE, 0, PR_FALSE }, + { /* opt_InputDB, */ 'i', PR_TRUE, 0, PR_FALSE }, + { /* opt_OutputDB, */ 'o', PR_TRUE, 0, PR_FALSE }, + { /* opt_Mailfile, */ 'm', PR_FALSE, 0, PR_FALSE }, + { /* opt_Prompt, */ 'p', PR_FALSE, 0, PR_FALSE }, + { /* opt_KeepRedundant, */ 'r', PR_FALSE, 0, PR_FALSE }, + { /* opt_KeepNoSMimeProfile,*/ 's', PR_FALSE, 0, PR_FALSE }, + { /* opt_Verbose, */ 'v', PR_FALSE, 0, PR_FALSE }, + { /* opt_KeepExpired, */ 'x', PR_FALSE, 0, PR_FALSE } +}; + +int +main(int argc, char **argv) +{ + CERTCertDBHandle *certHandle; + + PRFileInfo fileInfo; + PRFileDesc *mailfile = NULL; + PRFileDesc *dumpfile = NULL; + + char * pathname = 0; + char * fullname = 0; + char * newdbname = 0; + + PRBool removeExpired, requireProfile, singleEntry; + + SECStatus rv; + + secuCommand dbck; + dbck.numCommands = sizeof(dbck_commands) / sizeof(secuCommandFlag); + dbck.numOptions = sizeof(dbck_options) / sizeof(secuCommandFlag); + dbck.commands = dbck_commands; + dbck.options = dbck_options; + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + rv = SECU_ParseCommandLine(argc, argv, progName, &dbck); + + if (rv != SECSuccess) + Usage(progName); + + if (dbck.commands[cmd_LongUsage].activated) + LongUsage(progName); + + if (!dbck.commands[cmd_Debug].activated && + !dbck.commands[cmd_Recover].activated) { + PR_fprintf(PR_STDERR, "Please specify -D or -R.\n"); + Usage(progName); + } + + removeExpired = !(dbck.options[opt_KeepAll].activated || + dbck.options[opt_KeepExpired].activated); + + requireProfile = !(dbck.options[opt_KeepAll].activated || + dbck.options[opt_KeepNoSMimeProfile].activated); + + singleEntry = !(dbck.options[opt_KeepAll].activated || + dbck.options[opt_KeepRedundant].activated); + + if (dbck.options[opt_OutputDB].activated) { + newdbname = PL_strdup(dbck.options[opt_OutputDB].arg); + } else { + newdbname = PL_strdup("new_cert7.db"); + } + + /* Create a generic graph of the database. */ + if (dbck.options[opt_Mailfile].activated) { + mailfile = PR_Open("./mailfile", PR_RDWR | PR_CREATE_FILE, 00660); + if (!mailfile) { + fprintf(stderr, "Unable to create mailfile.\n"); + return -1; + } + } + + /* Dump all debugging info while running. */ + if (dbck.options[opt_Verbose].activated) { + if (dbck.options[opt_Dumpfile].activated) { + dumpfile = PR_Open(dbck.options[opt_Dumpfile].arg, + PR_RDWR | PR_CREATE_FILE, 00660); + } + if (!dumpfile) { + fprintf(stderr, "Unable to create dumpfile.\n"); + return -1; + } + } + + /* Set the cert database directory. */ + if (dbck.options[opt_CertDir].activated) { + SECU_ConfigDirectory(dbck.options[opt_CertDir].arg); + } + + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + SEC_Init(); + + certHandle = (CERTCertDBHandle *)PORT_ZAlloc(sizeof(CERTCertDBHandle)); + if (!certHandle) { + SECU_PrintError(progName, "unable to get database handle"); + return -1; + } + + /* Open the possibly corrupt database. */ + if (dbck.options[opt_InputDB].activated) { + pathname = SECU_ConfigDirectory(NULL); + fullname = PR_smprintf("%s/%s", pathname, + dbck.options[opt_InputDB].arg); + if (PR_GetFileInfo(fullname, &fileInfo) != PR_SUCCESS) { + fprintf(stderr, "Unable to read file \"%s\".\n", fullname); + return -1; + } + rv = CERT_OpenCertDBFilename(certHandle, fullname, PR_TRUE); + } else { + /* Use the default. */ + fullname = SECU_CertDBNameCallback(NULL, CERT_DB_FILE_VERSION); + if (PR_GetFileInfo(fullname, &fileInfo) != PR_SUCCESS) { + fprintf(stderr, "Unable to read file \"%s\".\n", fullname); + return -1; + } + rv = CERT_OpenCertDB(certHandle, PR_TRUE, + SECU_CertDBNameCallback, NULL); + } + + if (rv) { + SECU_PrintError(progName, "unable to open cert database"); + return -1; + } + + if (dbck.commands[cmd_Debug].activated) { + DBCK_DebugDB(certHandle, dumpfile, mailfile); + return 0; + } + +#ifdef DORECOVER + if (dbck.commands[cmd_Recover].activated) { + DBCK_ReconstructDBFromCerts(certHandle, newdbname, + dumpfile, removeExpired, + requireProfile, singleEntry, + dbck.options[opt_Prompt].activated); + return 0; + } +#endif + + if (mailfile) + PR_Close(mailfile); + if (dumpfile) + PR_Close(dumpfile); + if (certHandle) { + CERT_ClosePermCertDB(certHandle); + PORT_Free(certHandle); + } + return -1; +} diff --git a/security/nss/cmd/dbck/manifest.mn b/security/nss/cmd/dbck/manifest.mn new file mode 100644 index 000000000..74e66c49e --- /dev/null +++ b/security/nss/cmd/dbck/manifest.mn @@ -0,0 +1,49 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +DEFINES += -DNSPR20 + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +CSRCS = \ + dbck.c \ + $(NULL) + +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = dbm seccmd + +PROGRAM = dbck diff --git a/security/nss/cmd/dbtest/Makefile b/security/nss/cmd/dbtest/Makefile new file mode 100644 index 000000000..0ff13ae43 --- /dev/null +++ b/security/nss/cmd/dbtest/Makefile @@ -0,0 +1,88 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +ifdef XP_OS2_VACPP +CFLAGS += -I../modutil +endif + +ifeq (,$(filter-out WINNT WIN95 WIN16,$(OS_TARGET))) # omits WINCE +ifndef BUILD_OPT +ifndef NS_USE_GCC +LDFLAGS += /subsystem:console /profile /debug /machine:I386 /incremental:no +endif +OS_CFLAGS += -D_CONSOLE +endif +endif + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + +#include ../platlibs.mk + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +include ../platrules.mk + diff --git a/security/nss/cmd/dbtest/dbtest.c b/security/nss/cmd/dbtest/dbtest.c new file mode 100644 index 000000000..39f659522 --- /dev/null +++ b/security/nss/cmd/dbtest/dbtest.c @@ -0,0 +1,181 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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): + * Sonja Mirtitsch Sun Microsystems + * + * 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. + */ + +/* +** dbtest.c +** +** QA test for cert and key databases, especially to open +** database readonly (NSS_INIT_READONLY) and force initializations +** even if the databases cannot be opened (NSS_INIT_FORCEOPEN) +** +*/ +#include <stdio.h> +#include <string.h> + +#if defined(WIN32) +#include "fcntl.h" +#include "io.h" +#endif + +#include "secutil.h" + +#if defined(XP_UNIX) +#include <unistd.h> +#endif + +#include "nspr.h" +#include "prtypes.h" +#include "certdb.h" +#include "nss.h" +#include "../modutil/modutil.h" + +#include "plgetopt.h" + +static char *progName; + +char *dbDir = NULL; + +static char *dbName[]={"secmod.db", "cert8.db", "key3.db"}; +static char* dbprefix = ""; +static char* secmodName = "secmod.db"; +PRBool verbose; + + +static void Usage(const char *progName) +{ + printf("Usage: %s [-r] [-f] [-d dbdir ] \n", + progName); + printf("%-20s open database readonly (NSS_INIT_READONLY)\n", "-r"); + printf("%-20s Continue to force initializations even if the\n", "-f"); + printf("%-20s databases cannot be opened (NSS_INIT_FORCEOPEN)\n", " "); + printf("%-20s Directory with cert database (default is .\n", + "-d certdir"); + exit(1); +} + +int main(int argc, char **argv) +{ + PLOptState *optstate; + PLOptStatus optstatus; + + PRUint32 flags = 0; + PRBool useCommandLinePassword = PR_FALSE; + Error ret; + SECStatus rv; + char * dbString = NULL; + int i; + + progName = strrchr(argv[0], '/'); + if (!progName) + progName = strrchr(argv[0], '\\'); + progName = progName ? progName+1 : argv[0]; + + optstate = PL_CreateOptState(argc, argv, "rfd:h"); + + while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case 'h': + default : Usage(progName); break; + + case 'r': flags |= NSS_INIT_READONLY; break; + + case 'f': flags |= NSS_INIT_FORCEOPEN; break; + + case 'd': + dbDir = PORT_Strdup(optstate->value); + break; + + } + } + if (optstatus == PL_OPT_BAD) + Usage(progName); + + if (!dbDir) { + dbDir = SECU_DefaultSSLDir(); /* Look in $SSL_DIR */ + } + dbDir = SECU_ConfigDirectory(dbDir); + PR_fprintf(PR_STDERR, "dbdir selected is %s\n\n", dbDir); + + if( dbDir[0] == '\0') { + PR_fprintf(PR_STDERR, errStrings[DIR_DOESNT_EXIST_ERR], dbDir); + ret= DIR_DOESNT_EXIST_ERR; + goto loser; + } + + + PR_Init( PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + + /* get the status of the directory and databases and output message */ + if(PR_Access(dbDir, PR_ACCESS_EXISTS) != PR_SUCCESS) { + PR_fprintf(PR_STDERR, errStrings[DIR_DOESNT_EXIST_ERR], dbDir); + } else if(PR_Access(dbDir, PR_ACCESS_READ_OK) != PR_SUCCESS) { + PR_fprintf(PR_STDERR, errStrings[DIR_NOT_READABLE_ERR], dbDir); + } else { + if( !( flags & NSS_INIT_READONLY ) && + PR_Access(dbDir, PR_ACCESS_WRITE_OK) != PR_SUCCESS) { + PR_fprintf(PR_STDERR, errStrings[DIR_NOT_WRITEABLE_ERR], dbDir); + } + for (i=0;i<3;i++) { + dbString=PR_smprintf("%s/%s",dbDir,dbName[i]); + PR_fprintf(PR_STDOUT, "database checked is %s\n",dbString); + if(PR_Access(dbString, PR_ACCESS_EXISTS) != PR_SUCCESS) { + PR_fprintf(PR_STDERR, errStrings[FILE_DOESNT_EXIST_ERR], + dbString); + } else if(PR_Access(dbString, PR_ACCESS_READ_OK) != PR_SUCCESS) { + PR_fprintf(PR_STDERR, errStrings[FILE_NOT_READABLE_ERR], + dbString); + } else if( !( flags & NSS_INIT_READONLY ) && + PR_Access(dbString, PR_ACCESS_WRITE_OK) != PR_SUCCESS) { + PR_fprintf(PR_STDERR, errStrings[FILE_NOT_WRITEABLE_ERR], + dbString); + } + } + } + + rv = NSS_Initialize(SECU_ConfigDirectory(dbDir), dbprefix, dbprefix, + secmodName, flags); + if (rv != SECSuccess) { + SECU_PrintPRandOSError(progName); + ret=NSS_INITIALIZE_FAILED_ERR; + } else { + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + ret=SUCCESS; + } + +loser: + return ret; +} + diff --git a/security/nss/cmd/dbtest/makefile.win b/security/nss/cmd/dbtest/makefile.win new file mode 100644 index 000000000..5a60fd0af --- /dev/null +++ b/security/nss/cmd/dbtest/makefile.win @@ -0,0 +1,130 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +VERBOSE = 1 +include <manifest.mn> + +#cannot define PROGRAM in manifest compatibly with NT and UNIX +PROGRAM = dbtest +PROGRAM = ./$(OBJDIR)/$(PROGRAM).exe +include <$(DEPTH)\config\config.mak> + +# let manifest generate C_OBJS, it will prepend ./$(OBJDIR)/ +# rules.mak will append C_OBJS onto OBJS. +# OBJS = $(CSRCS:.c=.obj) + +# include files are looked for in $LINCS and $INCS. +# $LINCS is in manifest.mnw, computed from REQUIRES= +INCS = $(INCS) \ + -I$(DEPTH)/security/lib/cert \ + -I../include \ + $(NULL) + +IGNORE_ME = \ + -I$(DEPTH)/security/lib/key \ + -I$(DEPTH)/security/lib/util \ + $(NULL) + + +WINFE = $(DEPTH)/cmd/winfe/mkfiles$(MOZ_BITS)/x86Dbg + +# these files are the content of libdbm +DBM_LIB = \ + $(WINFE)/DB.obj \ + $(WINFE)/HASH.obj \ + $(WINFE)/H_BIGKEY.obj \ + $(WINFE)/H_PAGE.obj \ + $(WINFE)/H_LOG2.obj \ + $(WINFE)/H_FUNC.obj \ + $(WINFE)/HASH_BUF.obj \ + $(NULL) + +MOZ_LIBS = \ + $(WINFE)/ALLXPSTR.obj \ + $(WINFE)/XP_ERROR.obj \ + $(WINFE)/XPASSERT.obj \ + $(WINFE)/XP_REG.obj \ + $(WINFE)/XP_TRACE.obj \ + $(DBM_LIB) \ + $(WINFE)/XP_STR.obj \ + $(WINFE)/MKTEMP.obj \ + $(NULL) + +SEC_LIBS = \ + $(DIST)/lib/cert$(MOZ_BITS).lib \ + $(DIST)/lib/crypto$(MOZ_BITS).lib \ + $(DIST)/lib/hash$(MOZ_BITS).lib \ + $(DIST)/lib/key$(MOZ_BITS).lib \ + $(DIST)/lib/pkcs7$(MOZ_BITS).lib \ + $(DIST)/lib/secmod$(MOZ_BITS).lib \ + $(DIST)/lib/secutl$(MOZ_BITS).lib \ + $(DIST)/lib/ssl$(MOZ_BITS).lib \ + $(NULL) + +LLFLAGS = $(LLFLAGS) \ + ../lib/$(OBJDIR)/sectool$(MOZ_BITS).lib \ + $(SEC_LIBS) \ + $(MOZ_LIBS) \ + $(DEPTH)/nspr/src/$(OBJDIR)/getopt.obj \ + $(LIBNSPR) \ + $(NULL) + + +include <$(DEPTH)\config\rules.mak> + +INSTALL = $(MAKE_INSTALL) + +objs: $(OBJS) + +$(PROGRAM):: + $(INSTALL) $(DIST)/bin/pr3240.dll ./$(OBJDIR) + +programs: $(PROGRAM) + +install:: $(TARGETS) + $(INSTALL) $(TARGETS) $(DIST)/bin + + +symbols: + @echo "CSRCS = $(CSRCS)" + @echo "INCS = $(INCS)" + @echo "OBJS = $(OBJS)" + @echo "LIBRARY = $(LIBRARY)" + @echo "PROGRAM = $(PROGRAM)" + @echo "TARGETS = $(TARGETS)" + @echo "DIST = $(DIST)" + @echo "VERSION_NUMBER = $(VERSION_NUMBER)" + @echo "WINFE = $(WINFE)" + @echo "DBM_LIB = $(DBM_LIB)" + @echo "INSTALL = $(INSTALL)" + diff --git a/security/nss/cmd/dbtest/manifest.mn b/security/nss/cmd/dbtest/manifest.mn new file mode 100644 index 000000000..0f6888088 --- /dev/null +++ b/security/nss/cmd/dbtest/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +# This next line is used by .mk files +# and gets translated into $LINCS in manifest.mnw +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = seccmd dbm + +# DIRS = + +CSRCS = dbtest.c + +PROGRAM = dbtest + diff --git a/security/nss/cmd/derdump/Makefile b/security/nss/cmd/derdump/Makefile new file mode 100644 index 000000000..573c12cac --- /dev/null +++ b/security/nss/cmd/derdump/Makefile @@ -0,0 +1,76 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + + +include ../platrules.mk + diff --git a/security/nss/cmd/derdump/derdump.c b/security/nss/cmd/derdump/derdump.c new file mode 100644 index 000000000..603d5f772 --- /dev/null +++ b/security/nss/cmd/derdump/derdump.c @@ -0,0 +1,135 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "secutil.h" +#include "nss.h" +#include <errno.h> + +#if defined(XP_WIN) || (defined(__sun) && !defined(SVR4)) +#if !defined(WIN32) +extern int fprintf(FILE *, char *, ...); +#endif +#endif +#include "plgetopt.h" + +static void Usage(char *progName) +{ + fprintf(stderr, + "Usage: %s [-r] [-i input] [-o output]\n", + progName); + fprintf(stderr, "%-20s For formatted items, dump raw bytes as well\n", + "-r"); + fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n", + "-i input"); + fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n", + "-o output"); + exit(-1); +} + +int main(int argc, char **argv) +{ + char *progName; + int option; + FILE *outFile; + PRFileDesc *inFile; + SECItem der; + SECStatus rv; + int16 xp_error; + PRBool raw = PR_FALSE; + PLOptState *optstate; + PLOptStatus status; + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + /* Parse command line arguments */ + inFile = 0; + outFile = 0; + optstate = PL_CreateOptState(argc, argv, "i:o:r"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case 'i': + inFile = PR_Open(optstate->value, PR_RDONLY, 0); + if (!inFile) { + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", + progName, optstate->value); + return -1; + } + break; + + case 'o': + outFile = fopen(optstate->value, "w"); + if (!outFile) { + fprintf(stderr, "%s: unable to open \"%s\" for writing\n", + progName, optstate->value); + return -1; + } + break; + + case 'r': + raw = PR_TRUE; + break; + + default: + Usage(progName); + break; + } + } + if (status == PL_OPT_BAD) + Usage(progName); + + if (!inFile) inFile = PR_STDIN; + if (!outFile) outFile = stdout; + + rv = NSS_NoDB_Init(NULL); /* XXX */ + if (rv != SECSuccess) { + SECU_PrintPRandOSError(progName); + return -1; + } + + rv = SECU_ReadDERFromFile(&der, inFile, PR_FALSE); + if (rv == SECSuccess) { + rv = DER_PrettyPrint(outFile, &der, raw); + if (rv == SECSuccess) + return 0; + } + + xp_error = PORT_GetError(); + if (xp_error) { + SECU_PrintError(progName, "error %d", xp_error); + } + if (errno) { + SECU_PrintSystemError(progName, "errno=%d", errno); + } + return 1; +} diff --git a/security/nss/cmd/derdump/makefile.win b/security/nss/cmd/derdump/makefile.win new file mode 100644 index 000000000..9a9d4edef --- /dev/null +++ b/security/nss/cmd/derdump/makefile.win @@ -0,0 +1,130 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +VERBOSE = 1 +include <manifest.mn> + +#cannot define PROGRAM in manifest compatibly with NT and UNIX +PROGRAM = derdump +PROGRAM = ./$(OBJDIR)/$(PROGRAM).exe +include <$(DEPTH)\config\config.mak> + +# let manifest generate C_OBJS, it will prepend ./$(OBJDIR)/ +# rules.mak will append C_OBJS onto OBJS. +# OBJS = $(CSRCS:.c=.obj) + +# include files are looked for in $LINCS and $INCS. +# $LINCS is in manifest.mnw, computed from REQUIRES= +INCS = $(INCS) \ + -I$(DEPTH)/security/lib/cert \ + -I../include \ + $(NULL) + +IGNORE_ME = \ + -I$(DEPTH)/security/lib/key \ + -I$(DEPTH)/security/lib/util \ + $(NULL) + + +WINFE = $(DEPTH)/cmd/winfe/mkfiles$(MOZ_BITS)/x86Dbg + +# these files are the content of libdbm +DBM_LIB = \ + $(WINFE)/DB.obj \ + $(WINFE)/HASH.obj \ + $(WINFE)/H_BIGKEY.obj \ + $(WINFE)/H_PAGE.obj \ + $(WINFE)/H_LOG2.obj \ + $(WINFE)/H_FUNC.obj \ + $(WINFE)/HASH_BUF.obj \ + $(NULL) + +MOZ_LIBS = \ + $(WINFE)/ALLXPSTR.obj \ + $(WINFE)/XP_ERROR.obj \ + $(WINFE)/XPASSERT.obj \ + $(WINFE)/XP_REG.obj \ + $(WINFE)/XP_TRACE.obj \ + $(DBM_LIB) \ + $(WINFE)/XP_STR.obj \ + $(WINFE)/MKTEMP.obj \ + $(NULL) + +SEC_LIBS = \ + $(DIST)/lib/cert$(MOZ_BITS).lib \ + $(DIST)/lib/crypto$(MOZ_BITS).lib \ + $(DIST)/lib/hash$(MOZ_BITS).lib \ + $(DIST)/lib/key$(MOZ_BITS).lib \ + $(DIST)/lib/pkcs7$(MOZ_BITS).lib \ + $(DIST)/lib/secmod$(MOZ_BITS).lib \ + $(DIST)/lib/secutl$(MOZ_BITS).lib \ + $(DIST)/lib/ssl$(MOZ_BITS).lib \ + $(NULL) + +LLFLAGS = $(LLFLAGS) \ + ../lib/$(OBJDIR)/sectool$(MOZ_BITS).lib \ + $(SEC_LIBS) \ + $(MOZ_LIBS) \ + $(DEPTH)/nspr/src/$(OBJDIR)/getopt.obj \ + $(LIBNSPR) \ + $(NULL) + + +include <$(DEPTH)\config\rules.mak> + +INSTALL = $(MAKE_INSTALL) + +objs: $(OBJS) + +$(PROGRAM):: + $(INSTALL) $(DIST)/bin/pr3240.dll ./$(OBJDIR) + +programs: $(PROGRAM) + +install:: $(TARGETS) + $(INSTALL) $(TARGETS) $(DIST)/bin + + +symbols: + @echo "CSRCS = $(CSRCS)" + @echo "INCS = $(INCS)" + @echo "OBJS = $(OBJS)" + @echo "LIBRARY = $(LIBRARY)" + @echo "PROGRAM = $(PROGRAM)" + @echo "TARGETS = $(TARGETS)" + @echo "DIST = $(DIST)" + @echo "VERSION_NUMBER = $(VERSION_NUMBER)" + @echo "WINFE = $(WINFE)" + @echo "DBM_LIB = $(DBM_LIB)" + @echo "INSTALL = $(INSTALL)" + diff --git a/security/nss/cmd/derdump/manifest.mn b/security/nss/cmd/derdump/manifest.mn new file mode 100644 index 000000000..d9252cd0d --- /dev/null +++ b/security/nss/cmd/derdump/manifest.mn @@ -0,0 +1,49 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +# This next line is used by .mk files +# and gets translated into $LINCS in manifest.mnw +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = seccmd dbm + +DEFINES = -DNSPR20 + +CSRCS = derdump.c + +PROGRAM = derdump diff --git a/security/nss/cmd/digest/Makefile b/security/nss/cmd/digest/Makefile new file mode 100644 index 000000000..573c12cac --- /dev/null +++ b/security/nss/cmd/digest/Makefile @@ -0,0 +1,76 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + + +include ../platrules.mk + diff --git a/security/nss/cmd/digest/digest.c b/security/nss/cmd/digest/digest.c new file mode 100644 index 000000000..5405b1a3e --- /dev/null +++ b/security/nss/cmd/digest/digest.c @@ -0,0 +1,254 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "secutil.h" +#include "pk11func.h" +#include "secoid.h" + +#if defined(XP_WIN) || (defined(__sun) && !defined(SVR4)) +#if !defined(WIN32) +extern int fread(char *, size_t, size_t, FILE*); +extern int fwrite(char *, size_t, size_t, FILE*); +extern int fprintf(FILE *, char *, ...); +#endif +#endif + +#include "plgetopt.h" + +static SECOidData * +HashTypeToOID(HASH_HashType hashtype) +{ + SECOidTag hashtag; + + if (hashtype <= HASH_AlgNULL || hashtype >= HASH_AlgTOTAL) + return NULL; + + switch (hashtype) { + case HASH_AlgMD2: + hashtag = SEC_OID_MD2; + break; + case HASH_AlgMD5: + hashtag = SEC_OID_MD5; + break; + case HASH_AlgSHA1: + hashtag = SEC_OID_SHA1; + break; + default: + fprintf(stderr, "A new hash type has been added to HASH_HashType.\n"); + fprintf(stderr, "This program needs to be updated!\n"); + return NULL; + } + + return SECOID_FindOIDByTag(hashtag); +} + +static SECOidData * +HashNameToOID(const char *hashName) +{ + HASH_HashType htype; + SECOidData *hashOID; + + for (htype = HASH_AlgNULL + 1; htype < HASH_AlgTOTAL; htype++) { + hashOID = HashTypeToOID(htype); + if (PORT_Strcasecmp(hashName, hashOID->desc) == 0) + break; + } + + if (htype == HASH_AlgTOTAL) + return NULL; + + return hashOID; +} + +static void +Usage(char *progName) +{ + HASH_HashType htype; + + fprintf(stderr, + "Usage: %s -t type [-i input] [-o output]\n", + progName); + fprintf(stderr, "%-20s Specify the digest method (must be one of\n", + "-t type"); + fprintf(stderr, "%-20s ", ""); + for (htype = HASH_AlgNULL + 1; htype < HASH_AlgTOTAL; htype++) { + fprintf(stderr, HashTypeToOID(htype)->desc); + if (htype == (HASH_AlgTOTAL - 2)) + fprintf(stderr, " or "); + else if (htype != (HASH_AlgTOTAL - 1)) + fprintf(stderr, ", "); + } + fprintf(stderr, " (case ignored))\n"); + fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n", + "-i input"); + fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n", + "-o output"); + exit(-1); +} + +static int +DigestFile(FILE *outFile, FILE *inFile, SECOidData *hashOID) +{ + int nb; + unsigned char ibuf[4096], digest[32]; + PK11Context *hashcx; + unsigned int len; + SECStatus rv; + + hashcx = PK11_CreateDigestContext(hashOID->offset); + if (hashcx == NULL) { + return -1; + } + PK11_DigestBegin(hashcx); + + + for (;;) { + if (feof(inFile)) break; + nb = fread(ibuf, 1, sizeof(ibuf), inFile); + if (nb != sizeof(ibuf)) { + if (nb == 0) { + if (ferror(inFile)) { + PORT_SetError(SEC_ERROR_IO); + PK11_DestroyContext(hashcx,PR_TRUE); + return -1; + } + /* eof */ + break; + } + } + rv = PK11_DigestOp(hashcx, ibuf, nb); + if (rv != SECSuccess) { + PK11_DestroyContext(hashcx, PR_TRUE); + return -1; + } + } + + rv = PK11_DigestFinal(hashcx, digest, &len, 32); + PK11_DestroyContext(hashcx, PR_TRUE); + + if (rv != SECSuccess) return -1; + + nb = fwrite(digest, 1, len, outFile); + if (nb != len) { + PORT_SetError(SEC_ERROR_IO); + return -1; + } + + return 0; +} + +#include "nss.h" + +int +main(int argc, char **argv) +{ + char *progName; + int opt; + FILE *inFile, *outFile; + char *hashName; + SECOidData *hashOID; + PLOptState *optstate; + PLOptStatus status; + SECStatus rv; + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + inFile = NULL; + outFile = NULL; + hashName = NULL; + + rv = NSS_Init("/tmp"); + if (rv != SECSuccess) { + fprintf(stderr, "%s: NSS_Init failed in directory %s\n", + progName, "/tmp"); + return -1; + } + + /* + * Parse command line arguments + */ + optstate = PL_CreateOptState(argc, argv, "t:i:o:"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case '?': + Usage(progName); + break; + + case 'i': + inFile = fopen(optstate->value, "r"); + if (!inFile) { + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", + progName, optstate->value); + return -1; + } + break; + + case 'o': + outFile = fopen(optstate->value, "w"); + if (!outFile) { + fprintf(stderr, "%s: unable to open \"%s\" for writing\n", + progName, optstate->value); + return -1; + } + break; + + case 't': + hashName = strdup(optstate->value); + break; + } + } + + if (!hashName) Usage(progName); + + if (!inFile) inFile = stdin; + if (!outFile) outFile = stdout; + + hashOID = HashNameToOID(hashName); + if (hashOID == NULL) { + fprintf(stderr, "%s: invalid digest type\n", progName); + Usage(progName); + } + + if (DigestFile(outFile, inFile, hashOID)) { + fprintf(stderr, "%s: problem digesting data (%s)\n", + progName, SECU_Strerror(PORT_GetError())); + return -1; + } + + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + + return 0; +} diff --git a/security/nss/cmd/digest/makefile.win b/security/nss/cmd/digest/makefile.win new file mode 100644 index 000000000..e8ec27ca2 --- /dev/null +++ b/security/nss/cmd/digest/makefile.win @@ -0,0 +1,130 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +VERBOSE = 1 +include <manifest.mn> + +#cannot define PROGRAM in manifest compatibly with NT and UNIX +PROGRAM = digest +PROGRAM = ./$(OBJDIR)/$(PROGRAM).exe +include <$(DEPTH)\config\config.mak> + +# let manifest generate C_OBJS, it will prepend ./$(OBJDIR)/ +# rules.mak will append C_OBJS onto OBJS. +# OBJS = $(CSRCS:.c=.obj) + +# include files are looked for in $LINCS and $INCS. +# $LINCS is in manifest.mnw, computed from REQUIRES= +INCS = $(INCS) \ + -I$(DEPTH)/security/lib/cert \ + -I../include \ + $(NULL) + +IGNORE_ME = \ + -I$(DEPTH)/security/lib/key \ + -I$(DEPTH)/security/lib/util \ + $(NULL) + + +WINFE = $(DEPTH)/cmd/winfe/mkfiles$(MOZ_BITS)/x86Dbg + +# these files are the content of libdbm +DBM_LIB = \ + $(WINFE)/DB.obj \ + $(WINFE)/HASH.obj \ + $(WINFE)/H_BIGKEY.obj \ + $(WINFE)/H_PAGE.obj \ + $(WINFE)/H_LOG2.obj \ + $(WINFE)/H_FUNC.obj \ + $(WINFE)/HASH_BUF.obj \ + $(NULL) + +MOZ_LIBS = \ + $(WINFE)/ALLXPSTR.obj \ + $(WINFE)/XP_ERROR.obj \ + $(WINFE)/XPASSERT.obj \ + $(WINFE)/XP_REG.obj \ + $(WINFE)/XP_TRACE.obj \ + $(DBM_LIB) \ + $(WINFE)/XP_STR.obj \ + $(WINFE)/MKTEMP.obj \ + $(NULL) + +SEC_LIBS = \ + $(DIST)/lib/cert$(MOZ_BITS).lib \ + $(DIST)/lib/crypto$(MOZ_BITS).lib \ + $(DIST)/lib/hash$(MOZ_BITS).lib \ + $(DIST)/lib/key$(MOZ_BITS).lib \ + $(DIST)/lib/pkcs7$(MOZ_BITS).lib \ + $(DIST)/lib/secmod$(MOZ_BITS).lib \ + $(DIST)/lib/secutl$(MOZ_BITS).lib \ + $(DIST)/lib/ssl$(MOZ_BITS).lib \ + $(NULL) + +LLFLAGS = $(LLFLAGS) \ + ../lib/$(OBJDIR)/sectool$(MOZ_BITS).lib \ + $(SEC_LIBS) \ + $(MOZ_LIBS) \ + $(DEPTH)/nspr/src/$(OBJDIR)/getopt.obj \ + $(LIBNSPR) \ + $(NULL) + + +include <$(DEPTH)\config\rules.mak> + +INSTALL = $(MAKE_INSTALL) + +objs: $(OBJS) + +$(PROGRAM):: + $(INSTALL) $(DIST)/bin/pr3240.dll ./$(OBJDIR) + +programs: $(PROGRAM) + +install:: $(TARGETS) + $(INSTALL) $(TARGETS) $(DIST)/bin + + +symbols: + @echo "CSRCS = $(CSRCS)" + @echo "INCS = $(INCS)" + @echo "OBJS = $(OBJS)" + @echo "LIBRARY = $(LIBRARY)" + @echo "PROGRAM = $(PROGRAM)" + @echo "TARGETS = $(TARGETS)" + @echo "DIST = $(DIST)" + @echo "VERSION_NUMBER = $(VERSION_NUMBER)" + @echo "WINFE = $(WINFE)" + @echo "DBM_LIB = $(DBM_LIB)" + @echo "INSTALL = $(INSTALL)" + diff --git a/security/nss/cmd/digest/manifest.mn b/security/nss/cmd/digest/manifest.mn new file mode 100644 index 000000000..c84152d01 --- /dev/null +++ b/security/nss/cmd/digest/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +# This next line is used by .mk files +# and gets translated into $LINCS in manifest.mnw +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = seccmd dbm + +DEFINES = -DNSPR20 + +CSRCS = digest.c + +PROGRAM = digest + diff --git a/security/nss/cmd/ilock/Makefile b/security/nss/cmd/ilock/Makefile new file mode 100644 index 000000000..4e39ffc3f --- /dev/null +++ b/security/nss/cmd/ilock/Makefile @@ -0,0 +1,75 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/ilock/ilock.c b/security/nss/cmd/ilock/ilock.c new file mode 100644 index 000000000..3e2390b8d --- /dev/null +++ b/security/nss/cmd/ilock/ilock.c @@ -0,0 +1,199 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of 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: ilock.c +** Description: ilock.c is a unit test for nssilock. ilock.c +** tests the basic operation of nssilock. It should not be +** considered a complete test suite. +** +** To check that logging works, before running this test, +** define the following environment variables: +** +** +** +** +** +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <plgetopt.h> +#include <nspr.h> +#include <nssilock.h> + + +/* +** Test harness infrastructure +*/ +PRLogModuleInfo *lm; +PRLogModuleLevel msgLevel = PR_LOG_NONE; +PRIntn debug = 0; +PRUint32 failed_already = 0; +/* end Test harness infrastructure */ + +PRIntn optIterations = 1; /* default iterations */ + +PRIntn main(PRIntn argc, char *argv[]) +{ + PRIntn i; + { + /* + ** Get command line options + */ + PLOptStatus os; + PLOptState *opt = PL_CreateOptState(argc, argv, "hdvi:"); + + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) + { + if (PL_OPT_BAD == os) continue; + switch (opt->option) + { + case 'd': /* debug */ + debug = 1; + msgLevel = PR_LOG_ERROR; + break; + case 'v': /* verbose mode */ + msgLevel = PR_LOG_DEBUG; + break; + case 'i': /* number of iterations */ + optIterations = atol( opt->value ); + if ( 0 == optIterations ) optIterations = 1; /* coerce default on zero */ + break; + default: + break; + } + } + PL_DestroyOptState(opt); + } + + for ( i = 0 ; i < optIterations ; i++ ) { + /* First, test Lock */ + { + PZLock *pl; + PZMonitor *pm; + PZCondVar *cv; + PRStatus rc; + + pl = PZ_NewLock( nssILockOther ); + if ( NULL == pl ) { + failed_already = PR_TRUE; + goto Finished; + } + PZ_Lock( pl ); + + rc = PZ_Unlock( pl ); + if ( PR_FAILURE == rc ) { + failed_already = PR_TRUE; + goto Finished; + } + PZ_DestroyLock( pl ); + + /* now, test CVar */ + /* re-create the lock we just destroyed */ + pl = PZ_NewLock( nssILockOther ); + if ( NULL == pl ) { + failed_already = PR_TRUE; + goto Finished; + } + + cv = PZ_NewCondVar( pl ); + if ( NULL == cv ) { + failed_already = PR_TRUE; + goto Finished; + } + + PZ_Lock( pl ); + rc = PZ_NotifyCondVar( cv ); + if ( PR_FAILURE == rc ) { + failed_already = PR_TRUE; + goto Finished; + } + + rc = PZ_NotifyAllCondVar( cv ); + if ( PR_FAILURE == rc ) { + failed_already = PR_TRUE; + goto Finished; + } + + rc = PZ_WaitCondVar( cv, PR_SecondsToInterval(1)); + if ( PR_FAILURE == rc ) { + if ( PR_UNKNOWN_ERROR != PR_GetError()) { + failed_already = PR_TRUE; + goto Finished; + } + } + PZ_Unlock( pl ); + PZ_DestroyCondVar( cv ); + + /* Now, test Monitor */ + pm = PZ_NewMonitor( nssILockOther ); + if ( NULL == pm ) { + failed_already = PR_TRUE; + goto Finished; + } + + PZ_EnterMonitor( pm ); + + rc = PZ_Notify( pm ); + if ( PR_FAILURE == rc ) { + failed_already = PR_TRUE; + goto Finished; + } + rc = PZ_NotifyAll( pm ); + if ( PR_FAILURE == rc ) { + failed_already = PR_TRUE; + goto Finished; + } + rc = PZ_Wait( pm, PR_INTERVAL_NO_WAIT ); + if ( PR_FAILURE == rc ) { + failed_already = PR_TRUE; + goto Finished; + } + rc = PZ_ExitMonitor( pm ); + if ( PR_FAILURE == rc ) { + failed_already = PR_TRUE; + goto Finished; + } + PZ_DestroyMonitor( pm ); + } + } /* --- end for() --- */ + + +Finished: + if (debug) printf("%s\n", (failed_already)? "FAIL" : "PASS"); + return( (failed_already == PR_TRUE )? 1 : 0 ); +} /* main() */ +/* end ilock.c */ + diff --git a/security/nss/cmd/ilock/manifest.mn b/security/nss/cmd/ilock/manifest.mn new file mode 100644 index 000000000..4a8f7988c --- /dev/null +++ b/security/nss/cmd/ilock/manifest.mn @@ -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. +# +CORE_DEPTH = ../../.. + +DEFINES += -DNSPR20 + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +CSRCS = ilock.c + +PROGRAM = ilock +# PROGRAM = ./$(OBJDIR)/ilock.exe + diff --git a/security/nss/cmd/include/secnew.h b/security/nss/cmd/include/secnew.h new file mode 100644 index 000000000..eb4c30acd --- /dev/null +++ b/security/nss/cmd/include/secnew.h @@ -0,0 +1,163 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 __secnew_h_ +#define __secnew_h_ + +#include <stdio.h> + +typedef struct BERTemplateStr BERTemplate; +typedef struct BERParseStr BERParse; +typedef struct SECArbStr SECArb; + +/* + * An array of these structures define an encoding for an object using + * DER. The array is terminated with an entry where kind == 0. + */ +struct BERTemplateStr { + /* Kind of item to decode/encode */ + unsigned long kind; + + /* + * Offset from base of structure to SECItem that will hold + * decoded/encoded value. + */ + unsigned short offset; + + /* + * Used with DER_SET or DER_SEQUENCE. If not zero then points to a + * sub-template. The sub-template is filled in and completed before + * continuing on. + */ + BERTemplate *sub; + + /* + * Argument value, dependent on kind. Size of structure to allocate + * when kind==DER_POINTER For Context-Specific Implicit types its the + * underlying type to use. + */ + unsigned long arg; +}; + +/* + * an arbitrary object + */ +struct SECArbStr { + unsigned long tag; /* NOTE: does not support high tag form */ + unsigned long length; /* as reported in stream */ + union { + SECItem item; + struct { + int numSubs; + SECArb **subs; + } cons; + } body; +}; + +/* + * Decode a piece of der encoded data. + * "dest" points to a structure that will be filled in with the + * decoding results. + * "t" is a template structure which defines the shape of the + * expected data. + * "src" is the ber encoded data. + */ + +extern SECStatus BER_Decode(PRArenaPool * arena, void *dest, BERTemplate *t, + SECArb *arb); + + +/* + * 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 BER_Encode(PRArenaPool *arena, SECItem *dest, BERTemplate *t, + void *src); + +/* + * Client provided function that will get called with all the bytes + * passing through the parser + */ +typedef void (*BERFilterProc)(void *instance, unsigned char *buf, int length); + +/* + * Client provided function that can will be called after the tag and + * length information has been collected. It can be set up to be called + * either before or after the data has been colleced. + */ +typedef void (*BERNotifyProc)( + void *instance, SECArb *arb, int depth, PRBool before); + +extern BERParse *BER_ParseInit(PRArenaPool *arena, PRBool forceDER); +extern SECArb *BER_ParseFini(BERParse *h); +extern SECStatus BER_ParseSome(BERParse *h, unsigned char *buf, int len); + +extern void BER_SetFilter(BERParse *h, BERFilterProc proc, void *instance); +extern void BER_SetLeafStorage(BERParse *h, PRBool keep); +extern void BER_SetNotifyProc(BERParse *h, BERNotifyProc proc, void *instance, + PRBool beforeData); + +/* + * A BERUnparseProc is used as a callback to put the encoded SECArb tree + * tree to some stream. It returns PR_TRUE if the unparsing is to be + * aborted. + */ +typedef SECStatus (*BERUnparseProc)( + void *instance, unsigned char *data, int length, SECArb* arb); + +/* + * BER_Unparse walks the SECArb tree calling the BERUnparseProc with + * various pieces. It returns SECFailure if there was an error during that + * tree walk. + */ +extern SECStatus BER_Unparse(SECArb *arb, BERUnparseProc proc, void *instance); + +/* + * BER_ResolveLengths does a recursive walk through the tree generating + * non-zero entries for the length field of each node. It will fail if it + * discoveres a non-constructed node with a unknown length data field. + * Leaves are supposed to be of known length. + */ +extern SECStatus BER_ResolveLengths(SECArb *arb); + +/* + * BER_PRettyPrintArb will write an ASCII version of the tree to the FILE + * out. + */ +extern SECStatus BER_PrettyPrintArb(FILE *out, SECArb* a); + +#endif /* __secnew_h_ */ diff --git a/security/nss/cmd/keyutil/Makefile b/security/nss/cmd/keyutil/Makefile new file mode 100644 index 000000000..a2ed814be --- /dev/null +++ b/security/nss/cmd/keyutil/Makefile @@ -0,0 +1,73 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +include ../platrules.mk diff --git a/security/nss/cmd/keyutil/keyutil.c b/security/nss/cmd/keyutil/keyutil.c new file mode 100644 index 000000000..65e6ad8b0 --- /dev/null +++ b/security/nss/cmd/keyutil/keyutil.c @@ -0,0 +1,340 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "secutil.h" + +#if defined(XP_UNIX) +#include <unistd.h> +#include <sys/time.h> +#include <termios.h> +#endif + +#include "secopt.h" + +#if defined(XP_WIN) +#include <time.h> +#include <conio.h> +#endif + +#if defined(__sun) && !defined(SVR4) +extern int fclose(FILE*); +extern int fprintf(FILE *, char *, ...); +extern int getopt(int, char**, char*); +extern int isatty(int); +extern char *optarg; +extern char *sys_errlist[]; +#define strerror(errno) sys_errlist[errno] +#endif + +#include "nspr.h" +#include "prtypes.h" +#include "prtime.h" +#include "prlong.h" + +static char *progName; + +static SECStatus +ListKeys(SECKEYKeyDBHandle *handle, FILE *out) +{ + int rt; + + rt = SECU_PrintKeyNames(handle, out); + if (rt) { + SECU_PrintError(progName, "unable to list nicknames"); + return SECFailure; + } + return SECSuccess; +} + +static SECStatus +DumpPublicKey(SECKEYKeyDBHandle *handle, char *nickname, FILE *out) +{ + SECKEYLowPrivateKey *privKey; + SECKEYLowPublicKey *publicKey; + + /* check if key actually exists */ + if (SECU_CheckKeyNameExists(handle, nickname) == PR_FALSE) { + SECU_PrintError(progName, "the key \"%s\" does not exist", nickname); + return SECFailure; + } + + /* Read in key */ + privKey = SECU_GetPrivateKey(handle, nickname); + if (!privKey) { + return SECFailure; + } + + publicKey = SECKEY_LowConvertToPublicKey(privKey); + + /* Output public key (in the clear) */ + switch(publicKey->keyType) { + case rsaKey: + fprintf(out, "RSA Public-Key:\n"); + SECU_PrintInteger(out, &publicKey->u.rsa.modulus, "modulus", 1); + SECU_PrintInteger(out, &publicKey->u.rsa.publicExponent, + "publicExponent", 1); + break; + case dsaKey: + fprintf(out, "DSA Public-Key:\n"); + SECU_PrintInteger(out, &publicKey->u.dsa.params.prime, "prime", 1); + SECU_PrintInteger(out, &publicKey->u.dsa.params.subPrime, + "subPrime", 1); + SECU_PrintInteger(out, &publicKey->u.dsa.params.base, "base", 1); + SECU_PrintInteger(out, &publicKey->u.dsa.publicValue, "publicValue", 1); + break; + default: + fprintf(out, "unknown key type\n"); + break; + } + return SECSuccess; +} + +static SECStatus +DumpPrivateKey(SECKEYKeyDBHandle *handle, char *nickname, FILE *out) +{ + SECKEYLowPrivateKey *key; + + /* check if key actually exists */ + if (SECU_CheckKeyNameExists(handle, nickname) == PR_FALSE) { + SECU_PrintError(progName, "the key \"%s\" does not exist", nickname); + return SECFailure; + } + + /* Read in key */ + key = SECU_GetPrivateKey(handle, nickname); + if (!key) { + SECU_PrintError(progName, "error retrieving key"); + return SECFailure; + } + + switch(key->keyType) { + case rsaKey: + fprintf(out, "RSA Private-Key:\n"); + SECU_PrintInteger(out, &key->u.rsa.modulus, "modulus", 1); + SECU_PrintInteger(out, &key->u.rsa.publicExponent, "publicExponent", 1); + SECU_PrintInteger(out, &key->u.rsa.privateExponent, + "privateExponent", 1); + SECU_PrintInteger(out, &key->u.rsa.prime1, "prime1", 1); + SECU_PrintInteger(out, &key->u.rsa.prime2, "prime2", 1); + SECU_PrintInteger(out, &key->u.rsa.exponent1, "exponent1", 1); + SECU_PrintInteger(out, &key->u.rsa.exponent2, "exponent2", 1); + SECU_PrintInteger(out, &key->u.rsa.coefficient, "coefficient", 1); + break; + case dsaKey: + fprintf(out, "DSA Private-Key:\n"); + SECU_PrintInteger(out, &key->u.dsa.params.prime, "prime", 1); + SECU_PrintInteger(out, &key->u.dsa.params.subPrime, "subPrime", 1); + SECU_PrintInteger(out, &key->u.dsa.params.base, "base", 1); + SECU_PrintInteger(out, &key->u.dsa.publicValue, "publicValue", 1); + SECU_PrintInteger(out, &key->u.dsa.privateValue, "privateValue", 1); + break; + default: + fprintf(out, "unknown key type\n"); + break; + } + return SECSuccess; +} + +static SECStatus +ChangePassword(SECKEYKeyDBHandle *handle) +{ + SECStatus rv; + + /* Write out database with a new password */ + rv = SECU_ChangeKeyDBPassword(handle, NULL); + if (rv) { + SECU_PrintError(progName, "unable to change key password"); + } + return rv; +} + +static SECStatus +DeletePrivateKey (SECKEYKeyDBHandle *keyHandle, char *nickName) +{ + SECStatus rv; + + rv = SECU_DeleteKeyByName (keyHandle, nickName); + if (rv != SECSuccess) + fprintf(stderr, "%s: problem deleting private key (%s)\n", + progName, SECU_Strerror(PR_GetError())); + return (rv); + +} + + +static void +Usage(const char *progName) +{ + fprintf(stderr, + "Usage: %s -p name [-d keydir]\n", progName); + fprintf(stderr, + " %s -P name [-d keydir]\n", progName); + fprintf(stderr, + " %s -D name [-d keydir]\n", progName); + fprintf(stderr, + " %s -l [-d keydir]\n", progName); + fprintf(stderr, + " %s -c [-d keydir]\n", progName); + + fprintf(stderr, "%-20s Pretty print public key info for named key\n", + "-p nickname"); + fprintf(stderr, "%-20s Pretty print private key info for named key\n", + "-P nickname"); + fprintf(stderr, "%-20s Delete named private key from the key database\n", + "-D nickname"); + fprintf(stderr, "%-20s List the nicknames for the keys in a database\n", + "-l"); + fprintf(stderr, "%-20s Change the key database password\n", + "-c"); + fprintf(stderr, "\n"); + fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", + "-d keydir"); + + exit(-1); +} + +int main(int argc, char **argv) +{ + int o, changePassword, deleteKey, dumpPublicKey, dumpPrivateKey, list; + char *nickname; + SECStatus rv; + SECKEYKeyDBHandle *keyHandle; + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + /* Parse command line arguments */ + changePassword = deleteKey = dumpPublicKey = dumpPrivateKey = list = 0; + nickname = NULL; + + while ((o = getopt(argc, argv, "ADP:cd:glp:")) != -1) { + switch (o) { + case '?': + Usage(progName); + break; + + case 'A': + fprintf(stderr, "%s: Can no longer add a key.", progName); + fprintf(stderr, " Use pkcs12 to import a key.\n\n"); + Usage(progName); + break; + + case 'D': + deleteKey = 1; + nickname = optarg; + break; + + case 'P': + dumpPrivateKey = 1; + nickname = optarg; + break; + + case 'c': + changePassword = 1; + break; + + case 'd': + SECU_ConfigDirectory(optarg); + break; + + case 'g': + fprintf(stderr, "%s: Can no longer generate a key.", progName); + fprintf(stderr, " Use certutil to generate a cert request.\n\n"); + Usage(progName); + break; + + case 'l': + list = 1; + break; + + case 'p': + dumpPublicKey = 1; + nickname = optarg; + break; + } + } + + if (dumpPublicKey+changePassword+dumpPrivateKey+list+deleteKey != 1) + Usage(progName); + + if ((list || changePassword) && nickname) + Usage(progName); + + if ((dumpPublicKey || dumpPrivateKey || deleteKey) && !nickname) + Usage(progName); + + + /* Call the libsec initialization routines */ + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + SEC_Init(); + + /* + * XXX Note that the following opens the key database writable. + * If dumpPublicKey or dumpPrivateKey or list, though, we only want + * to open it read-only. There needs to be a better interface + * to the initialization routines so that we can specify which way + * to open it. + */ + rv = SECU_PKCS11Init(); + if (rv != SECSuccess) { + SECU_PrintError(progName, "SECU_PKCS11Init failed"); + return -1; + } + + keyHandle = SECKEY_GetDefaultKeyDB(); + if (keyHandle == NULL) { + SECU_PrintError(progName, "could not open key database"); + return -1; + } + + if (dumpPublicKey) { + rv = DumpPublicKey(keyHandle, nickname, stdout); + } else + if (changePassword) { + rv = ChangePassword(keyHandle); + } else + if (dumpPrivateKey) { + rv = DumpPrivateKey(keyHandle, nickname, stdout); + } else + if (list) { + rv = ListKeys(keyHandle, stdout); + } else + if (deleteKey) { + rv = DeletePrivateKey(keyHandle, nickname); + } + + + return rv ? -1 : 0; +} diff --git a/security/nss/cmd/keyutil/manifest.mn b/security/nss/cmd/keyutil/manifest.mn new file mode 100644 index 000000000..e20a3d330 --- /dev/null +++ b/security/nss/cmd/keyutil/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +DEFINES += -DNSPR20 + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +CSRCS = \ + keyutil.c \ + $(NULL) + +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = seccmd dbm + + +PROGRAM = keyutil diff --git a/security/nss/cmd/lib/Makefile b/security/nss/cmd/lib/Makefile new file mode 100644 index 000000000..217e25668 --- /dev/null +++ b/security/nss/cmd/lib/Makefile @@ -0,0 +1,76 @@ +#! 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/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). # +####################################################################### + +$(OBJDIR)/secerror$(OBJ_SUFFIX): NSPRerrs.h SECerrs.h SSLerrs.h + diff --git a/security/nss/cmd/lib/NSPRerrs.h b/security/nss/cmd/lib/NSPRerrs.h new file mode 100644 index 000000000..5e2cd793e --- /dev/null +++ b/security/nss/cmd/lib/NSPRerrs.h @@ -0,0 +1,150 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ +/* General NSPR 2.0 errors */ +/* Caller must #include "prerror.h" */ + +ER2( PR_OUT_OF_MEMORY_ERROR, "Memory allocation attempt failed." ) +ER2( PR_BAD_DESCRIPTOR_ERROR, "Invalid file descriptor." ) +ER2( PR_WOULD_BLOCK_ERROR, "The operation would have blocked." ) +ER2( PR_ACCESS_FAULT_ERROR, "Invalid memory address argument." ) +ER2( PR_INVALID_METHOD_ERROR, "Invalid function for file type." ) +ER2( PR_ILLEGAL_ACCESS_ERROR, "Invalid memory address argument." ) +ER2( PR_UNKNOWN_ERROR, "Some unknown error has occurred." ) +ER2( PR_PENDING_INTERRUPT_ERROR,"Operation interrupted by another thread." ) +ER2( PR_NOT_IMPLEMENTED_ERROR, "function not implemented." ) +ER2( PR_IO_ERROR, "I/O function error." ) +ER2( PR_IO_TIMEOUT_ERROR, "I/O operation timed out." ) +ER2( PR_IO_PENDING_ERROR, "I/O operation on busy file descriptor." ) +ER2( PR_DIRECTORY_OPEN_ERROR, "The directory could not be opened." ) +ER2( PR_INVALID_ARGUMENT_ERROR, "Invalid function argument." ) +ER2( PR_ADDRESS_NOT_AVAILABLE_ERROR, "Network address not available (in use?)." ) +ER2( PR_ADDRESS_NOT_SUPPORTED_ERROR, "Network address type not supported." ) +ER2( PR_IS_CONNECTED_ERROR, "Already connected." ) +ER2( PR_BAD_ADDRESS_ERROR, "Network address is invalid." ) +ER2( PR_ADDRESS_IN_USE_ERROR, "Local Network address is in use." ) +ER2( PR_CONNECT_REFUSED_ERROR, "Connection refused by peer." ) +ER2( PR_NETWORK_UNREACHABLE_ERROR, "Network address is presently unreachable." ) +ER2( PR_CONNECT_TIMEOUT_ERROR, "Connection attempt timed out." ) +ER2( PR_NOT_CONNECTED_ERROR, "Network file descriptor is not connected." ) +ER2( PR_LOAD_LIBRARY_ERROR, "Failure to load dynamic library." ) +ER2( PR_UNLOAD_LIBRARY_ERROR, "Failure to unload dynamic library." ) +ER2( PR_FIND_SYMBOL_ERROR, +"Symbol not found in any of the loaded dynamic libraries." ) +ER2( PR_INSUFFICIENT_RESOURCES_ERROR, "Insufficient system resources." ) +ER2( PR_DIRECTORY_LOOKUP_ERROR, +"A directory lookup on a network address has failed." ) +ER2( PR_TPD_RANGE_ERROR, +"Attempt to access a TPD key that is out of range." ) +ER2( PR_PROC_DESC_TABLE_FULL_ERROR, "Process open FD table is full." ) +ER2( PR_SYS_DESC_TABLE_FULL_ERROR, "System open FD table is full." ) +ER2( PR_NOT_SOCKET_ERROR, +"Network operation attempted on non-network file descriptor." ) +ER2( PR_NOT_TCP_SOCKET_ERROR, +"TCP-specific function attempted on a non-TCP file descriptor." ) +ER2( PR_SOCKET_ADDRESS_IS_BOUND_ERROR, "TCP file descriptor is already bound." ) +ER2( PR_NO_ACCESS_RIGHTS_ERROR, "Access Denied." ) +ER2( PR_OPERATION_NOT_SUPPORTED_ERROR, +"The requested operation is not supported by the platform." ) +ER2( PR_PROTOCOL_NOT_SUPPORTED_ERROR, +"The host operating system does not support the protocol requested." ) +ER2( PR_REMOTE_FILE_ERROR, "Access to the remote file has been severed." ) +ER2( PR_BUFFER_OVERFLOW_ERROR, +"The value requested is too large to be stored in the data buffer provided." ) +ER2( PR_CONNECT_RESET_ERROR, "TCP connection reset by peer." ) +ER2( PR_RANGE_ERROR, "Unused." ) +ER2( PR_DEADLOCK_ERROR, "The operation would have deadlocked." ) +ER2( PR_FILE_IS_LOCKED_ERROR, "The file is already locked." ) +ER2( PR_FILE_TOO_BIG_ERROR, +"Write would result in file larger than the system allows." ) +ER2( PR_NO_DEVICE_SPACE_ERROR, "The device for storing the file is full." ) +ER2( PR_PIPE_ERROR, "Unused." ) +ER2( PR_NO_SEEK_DEVICE_ERROR, "Unused." ) +ER2( PR_IS_DIRECTORY_ERROR, +"Cannot perform a normal file operation on a directory." ) +ER2( PR_LOOP_ERROR, "Symbolic link loop." ) +ER2( PR_NAME_TOO_LONG_ERROR, "File name is too long." ) +ER2( PR_FILE_NOT_FOUND_ERROR, "File not found." ) +ER2( PR_NOT_DIRECTORY_ERROR, +"Cannot perform directory operation on a normal file." ) +ER2( PR_READ_ONLY_FILESYSTEM_ERROR, +"Cannot write to a read-only file system." ) +ER2( PR_DIRECTORY_NOT_EMPTY_ERROR, +"Cannot delete a directory that is not empty." ) +ER2( PR_FILESYSTEM_MOUNTED_ERROR, +"Cannot delete or rename a file object while the file system is busy." ) +ER2( PR_NOT_SAME_DEVICE_ERROR, +"Cannot rename a file to a file system on another device." ) +ER2( PR_DIRECTORY_CORRUPTED_ERROR, +"The directory object in the file system is corrupted." ) +ER2( PR_FILE_EXISTS_ERROR, +"Cannot create or rename a filename that already exists." ) +ER2( PR_MAX_DIRECTORY_ENTRIES_ERROR, +"Directory is full. No additional filenames may be added." ) +ER2( PR_INVALID_DEVICE_STATE_ERROR, +"The required device was in an invalid state." ) +ER2( PR_DEVICE_IS_LOCKED_ERROR, "The device is locked." ) +ER2( PR_NO_MORE_FILES_ERROR, "No more entries in the directory." ) +ER2( PR_END_OF_FILE_ERROR, "Encountered end of file." ) +ER2( PR_FILE_SEEK_ERROR, "Seek error." ) +ER2( PR_FILE_IS_BUSY_ERROR, "The file is busy." ) +ER2( PR_IN_PROGRESS_ERROR, +"Operation is still in progress (probably a non-blocking connect)." ) +ER2( PR_ALREADY_INITIATED_ERROR, +"Operation has already been initiated (probably a non-blocking connect)." ) + +#ifdef PR_GROUP_EMPTY_ERROR +ER2( PR_GROUP_EMPTY_ERROR, "The wait group is empty." ) +#endif + +#ifdef PR_INVALID_STATE_ERROR +ER2( PR_INVALID_STATE_ERROR, "Object state improper for request." ) +#endif + +#ifdef PR_NETWORK_DOWN_ERROR +ER2( PR_NETWORK_DOWN_ERROR, "Network is down." ) +#endif + +#ifdef PR_SOCKET_SHUTDOWN_ERROR +ER2( PR_SOCKET_SHUTDOWN_ERROR, "The socket was previously shut down." ) +#endif + +#ifdef PR_CONNECT_ABORTED_ERROR +ER2( PR_CONNECT_ABORTED_ERROR, "TCP Connection aborted." ) +#endif + +#ifdef PR_HOST_UNREACHABLE_ERROR +ER2( PR_HOST_UNREACHABLE_ERROR, "Host is unreachable." ) +#endif + +/* always last */ +ER2( PR_MAX_ERROR, "Placeholder for the end of the list" ) diff --git a/security/nss/cmd/lib/SECerrs.h b/security/nss/cmd/lib/SECerrs.h new file mode 100644 index 000000000..e566e3983 --- /dev/null +++ b/security/nss/cmd/lib/SECerrs.h @@ -0,0 +1,476 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* General security error codes */ +/* Caller must #include "secerr.h" */ + +ER3(SEC_ERROR_IO, SEC_ERROR_BASE + 0, +"An I/O error occurred during security authorization.") + +ER3(SEC_ERROR_LIBRARY_FAILURE, SEC_ERROR_BASE + 1, +"security library failure.") + +ER3(SEC_ERROR_BAD_DATA, SEC_ERROR_BASE + 2, +"security library: received bad data.") + +ER3(SEC_ERROR_OUTPUT_LEN, SEC_ERROR_BASE + 3, +"security library: output length error.") + +ER3(SEC_ERROR_INPUT_LEN, SEC_ERROR_BASE + 4, +"security library has experienced an input length error.") + +ER3(SEC_ERROR_INVALID_ARGS, SEC_ERROR_BASE + 5, +"security library: invalid arguments.") + +ER3(SEC_ERROR_INVALID_ALGORITHM, SEC_ERROR_BASE + 6, +"security library: invalid algorithm.") + +ER3(SEC_ERROR_INVALID_AVA, SEC_ERROR_BASE + 7, +"security library: invalid AVA.") + +ER3(SEC_ERROR_INVALID_TIME, SEC_ERROR_BASE + 8, +"Improperly formatted time string.") + +ER3(SEC_ERROR_BAD_DER, SEC_ERROR_BASE + 9, +"security library: improperly formatted DER-encoded message.") + +ER3(SEC_ERROR_BAD_SIGNATURE, SEC_ERROR_BASE + 10, +"Peer's certificate has an invalid signature.") + +ER3(SEC_ERROR_EXPIRED_CERTIFICATE, SEC_ERROR_BASE + 11, +"Peer's Certificate has expired.") + +ER3(SEC_ERROR_REVOKED_CERTIFICATE, SEC_ERROR_BASE + 12, +"Peer's Certificate has been revoked.") + +ER3(SEC_ERROR_UNKNOWN_ISSUER, SEC_ERROR_BASE + 13, +"Peer's Certificate issuer is not recognized.") + +ER3(SEC_ERROR_BAD_KEY, SEC_ERROR_BASE + 14, +"Peer's public key is invalid.") + +ER3(SEC_ERROR_BAD_PASSWORD, SEC_ERROR_BASE + 15, +"The security password entered is incorrect.") + +ER3(SEC_ERROR_RETRY_PASSWORD, SEC_ERROR_BASE + 16, +"New password entered incorrectly. Please try again.") + +ER3(SEC_ERROR_NO_NODELOCK, SEC_ERROR_BASE + 17, +"security library: no nodelock.") + +ER3(SEC_ERROR_BAD_DATABASE, SEC_ERROR_BASE + 18, +"security library: bad database.") + +ER3(SEC_ERROR_NO_MEMORY, SEC_ERROR_BASE + 19, +"security library: memory allocation failure.") + +ER3(SEC_ERROR_UNTRUSTED_ISSUER, SEC_ERROR_BASE + 20, +"Peer's certificate issuer has been marked as not trusted by the user.") + +ER3(SEC_ERROR_UNTRUSTED_CERT, SEC_ERROR_BASE + 21, +"Peer's certificate has been marked as not trusted by the user.") + +ER3(SEC_ERROR_DUPLICATE_CERT, (SEC_ERROR_BASE + 22), +"Certificate already exists in your database.") + +ER3(SEC_ERROR_DUPLICATE_CERT_NAME, (SEC_ERROR_BASE + 23), +"Downloaded certificate's name duplicates one already in your database.") + +ER3(SEC_ERROR_ADDING_CERT, (SEC_ERROR_BASE + 24), +"Error adding certificate to database.") + +ER3(SEC_ERROR_FILING_KEY, (SEC_ERROR_BASE + 25), +"Error refiling the key for this certificate.") + +ER3(SEC_ERROR_NO_KEY, (SEC_ERROR_BASE + 26), +"The private key for this certificate cannot be found in key database") + +ER3(SEC_ERROR_CERT_VALID, (SEC_ERROR_BASE + 27), +"This certificate is valid.") + +ER3(SEC_ERROR_CERT_NOT_VALID, (SEC_ERROR_BASE + 28), +"This certificate is not valid.") + +ER3(SEC_ERROR_CERT_NO_RESPONSE, (SEC_ERROR_BASE + 29), +"Cert Library: No Response") + +ER3(SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE, (SEC_ERROR_BASE + 30), +"The certificate issuer's certificate has expired. Check your system date and time.") + +ER3(SEC_ERROR_CRL_EXPIRED, (SEC_ERROR_BASE + 31), +"The CRL for the certificate's issuer has expired. Update it or check your system data and time.") + +ER3(SEC_ERROR_CRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 32), +"The CRL for the certificate's issuer has an invalid signature.") + +ER3(SEC_ERROR_CRL_INVALID, (SEC_ERROR_BASE + 33), +"New CRL has an invalid format.") + +ER3(SEC_ERROR_EXTENSION_VALUE_INVALID, (SEC_ERROR_BASE + 34), +"Certificate extension value is invalid.") + +ER3(SEC_ERROR_EXTENSION_NOT_FOUND, (SEC_ERROR_BASE + 35), +"Certificate extension not found.") + +ER3(SEC_ERROR_CA_CERT_INVALID, (SEC_ERROR_BASE + 36), +"Issuer certificate is invalid.") + +ER3(SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID, (SEC_ERROR_BASE + 37), +"Certificate path length constraint is invalid.") + +ER3(SEC_ERROR_CERT_USAGES_INVALID, (SEC_ERROR_BASE + 38), +"Certificate usages field is invalid.") + +ER3(SEC_INTERNAL_ONLY, (SEC_ERROR_BASE + 39), +"**Internal ONLY module**") + +ER3(SEC_ERROR_INVALID_KEY, (SEC_ERROR_BASE + 40), +"The key does not support the requested operation.") + +ER3(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION, (SEC_ERROR_BASE + 41), +"Certificate contains unknown critical extension.") + +ER3(SEC_ERROR_OLD_CRL, (SEC_ERROR_BASE + 42), +"New CRL is not later than the current one.") + +ER3(SEC_ERROR_NO_EMAIL_CERT, (SEC_ERROR_BASE + 43), +"Not encrypted or signed: you do not yet have an email certificate.") + +ER3(SEC_ERROR_NO_RECIPIENT_CERTS_QUERY, (SEC_ERROR_BASE + 44), +"Not encrypted: you do not have certificates for each of the recipients.") + +ER3(SEC_ERROR_NOT_A_RECIPIENT, (SEC_ERROR_BASE + 45), +"Cannot decrypt: you are not a recipient, or matching certificate and \ +private key not found.") + +ER3(SEC_ERROR_PKCS7_KEYALG_MISMATCH, (SEC_ERROR_BASE + 46), +"Cannot decrypt: key encryption algorithm does not match your certificate.") + +ER3(SEC_ERROR_PKCS7_BAD_SIGNATURE, (SEC_ERROR_BASE + 47), +"Signature verification failed: no signer found, too many signers found, \ +or improper or corrupted data.") + +ER3(SEC_ERROR_UNSUPPORTED_KEYALG, (SEC_ERROR_BASE + 48), +"Unsupported or unknown key algorithm.") + +ER3(SEC_ERROR_DECRYPTION_DISALLOWED, (SEC_ERROR_BASE + 49), +"Cannot decrypt: encrypted using a disallowed algorithm or key size.") + + +/* Fortezza Alerts */ +ER3(XP_SEC_FORTEZZA_BAD_CARD, (SEC_ERROR_BASE + 50), +"Fortezza card has not been properly initialized. \ +Please remove it and return it to your issuer.") + +ER3(XP_SEC_FORTEZZA_NO_CARD, (SEC_ERROR_BASE + 51), +"No Fortezza cards Found") + +ER3(XP_SEC_FORTEZZA_NONE_SELECTED, (SEC_ERROR_BASE + 52), +"No Fortezza card selected") + +ER3(XP_SEC_FORTEZZA_MORE_INFO, (SEC_ERROR_BASE + 53), +"Please select a personality to get more info on") + +ER3(XP_SEC_FORTEZZA_PERSON_NOT_FOUND, (SEC_ERROR_BASE + 54), +"Personality not found") + +ER3(XP_SEC_FORTEZZA_NO_MORE_INFO, (SEC_ERROR_BASE + 55), +"No more information on that Personality") + +ER3(XP_SEC_FORTEZZA_BAD_PIN, (SEC_ERROR_BASE + 56), +"Invalid Pin") + +ER3(XP_SEC_FORTEZZA_PERSON_ERROR, (SEC_ERROR_BASE + 57), +"Couldn't initialize Fortezza personalities.") +/* end fortezza alerts. */ + +ER3(SEC_ERROR_NO_KRL, (SEC_ERROR_BASE + 58), +"No KRL for this site's certificate has been found.") + +ER3(SEC_ERROR_KRL_EXPIRED, (SEC_ERROR_BASE + 59), +"The KRL for this site's certificate has expired.") + +ER3(SEC_ERROR_KRL_BAD_SIGNATURE, (SEC_ERROR_BASE + 60), +"The KRL for this site's certificate has an invalid signature.") + +ER3(SEC_ERROR_REVOKED_KEY, (SEC_ERROR_BASE + 61), +"The key for this site's certificate has been revoked.") + +ER3(SEC_ERROR_KRL_INVALID, (SEC_ERROR_BASE + 62), +"New KRL has an invalid format.") + +ER3(SEC_ERROR_NEED_RANDOM, (SEC_ERROR_BASE + 63), +"security library: need random data.") + +ER3(SEC_ERROR_NO_MODULE, (SEC_ERROR_BASE + 64), +"security library: no security module can perform the requested operation.") + +ER3(SEC_ERROR_NO_TOKEN, (SEC_ERROR_BASE + 65), +"The security card or token does not exist, needs to be initialized, or has been removed.") + +ER3(SEC_ERROR_READ_ONLY, (SEC_ERROR_BASE + 66), +"security library: read-only database.") + +ER3(SEC_ERROR_NO_SLOT_SELECTED, (SEC_ERROR_BASE + 67), +"No slot or token was selected.") + +ER3(SEC_ERROR_CERT_NICKNAME_COLLISION, (SEC_ERROR_BASE + 68), +"A certificate with the same nickname already exists.") + +ER3(SEC_ERROR_KEY_NICKNAME_COLLISION, (SEC_ERROR_BASE + 69), +"A key with the same nickname already exists.") + +ER3(SEC_ERROR_SAFE_NOT_CREATED, (SEC_ERROR_BASE + 70), +"error while creating safe object") + +ER3(SEC_ERROR_BAGGAGE_NOT_CREATED, (SEC_ERROR_BASE + 71), +"error while creating baggage object") + +ER3(XP_JAVA_REMOVE_PRINCIPAL_ERROR, (SEC_ERROR_BASE + 72), +"Couldn't remove the principal") + +ER3(XP_JAVA_DELETE_PRIVILEGE_ERROR, (SEC_ERROR_BASE + 73), +"Couldn't delete the privilege") + +ER3(XP_JAVA_CERT_NOT_EXISTS_ERROR, (SEC_ERROR_BASE + 74), +"This principal doesn't have a certificate") + +ER3(SEC_ERROR_BAD_EXPORT_ALGORITHM, (SEC_ERROR_BASE + 75), +"Required algorithm is not allowed.") + +ER3(SEC_ERROR_EXPORTING_CERTIFICATES, (SEC_ERROR_BASE + 76), +"Error attempting to export certificates.") + +ER3(SEC_ERROR_IMPORTING_CERTIFICATES, (SEC_ERROR_BASE + 77), +"Error attempting to import certificates.") + +ER3(SEC_ERROR_PKCS12_DECODING_PFX, (SEC_ERROR_BASE + 78), +"Unable to import. Decoding error. File not valid.") + +ER3(SEC_ERROR_PKCS12_INVALID_MAC, (SEC_ERROR_BASE + 79), +"Unable to import. Invalid MAC. Incorrect password or corrupt file.") + +ER3(SEC_ERROR_PKCS12_UNSUPPORTED_MAC_ALGORITHM, (SEC_ERROR_BASE + 80), +"Unable to import. MAC algorithm not supported.") + +ER3(SEC_ERROR_PKCS12_UNSUPPORTED_TRANSPORT_MODE,(SEC_ERROR_BASE + 81), +"Unable to import. Only password integrity and privacy modes supported.") + +ER3(SEC_ERROR_PKCS12_CORRUPT_PFX_STRUCTURE, (SEC_ERROR_BASE + 82), +"Unable to import. File structure is corrupt.") + +ER3(SEC_ERROR_PKCS12_UNSUPPORTED_PBE_ALGORITHM, (SEC_ERROR_BASE + 83), +"Unable to import. Encryption algorithm not supported.") + +ER3(SEC_ERROR_PKCS12_UNSUPPORTED_VERSION, (SEC_ERROR_BASE + 84), +"Unable to import. File version not supported.") + +ER3(SEC_ERROR_PKCS12_PRIVACY_PASSWORD_INCORRECT,(SEC_ERROR_BASE + 85), +"Unable to import. Incorrect privacy password.") + +ER3(SEC_ERROR_PKCS12_CERT_COLLISION, (SEC_ERROR_BASE + 86), +"Unable to import. Same nickname already exists in database.") + +ER3(SEC_ERROR_USER_CANCELLED, (SEC_ERROR_BASE + 87), +"The user pressed cancel.") + +ER3(SEC_ERROR_PKCS12_DUPLICATE_DATA, (SEC_ERROR_BASE + 88), +"Not imported, already in database.") + +ER3(SEC_ERROR_MESSAGE_SEND_ABORTED, (SEC_ERROR_BASE + 89), +"Message not sent.") + +ER3(SEC_ERROR_INADEQUATE_KEY_USAGE, (SEC_ERROR_BASE + 90), +"Certificate key usage inadequate for attempted operation.") + +ER3(SEC_ERROR_INADEQUATE_CERT_TYPE, (SEC_ERROR_BASE + 91), +"Certificate type not approved for application.") + +ER3(SEC_ERROR_CERT_ADDR_MISMATCH, (SEC_ERROR_BASE + 92), +"Address in signing certificate does not match address in message headers.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_IMPORT_KEY, (SEC_ERROR_BASE + 93), +"Unable to import. Error attempting to import private key.") + +ER3(SEC_ERROR_PKCS12_IMPORTING_CERT_CHAIN, (SEC_ERROR_BASE + 94), +"Unable to import. Error attempting to import certificate chain.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME, (SEC_ERROR_BASE + 95), +"Unable to export. Unable to locate certificate or key by nickname.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY, (SEC_ERROR_BASE + 96), +"Unable to export. Private Key could not be located and exported.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_WRITE, (SEC_ERROR_BASE + 97), +"Unable to export. Unable to write the export file.") + +ER3(SEC_ERROR_PKCS12_UNABLE_TO_READ, (SEC_ERROR_BASE + 98), +"Unable to import. Unable to read the import file.") + +ER3(SEC_ERROR_PKCS12_KEY_DATABASE_NOT_INITIALIZED, (SEC_ERROR_BASE + 99), +"Unable to export. Key database corrupt or deleted.") + +ER3(SEC_ERROR_KEYGEN_FAIL, (SEC_ERROR_BASE + 100), +"Unable to generate public/private key pair.") + +ER3(SEC_ERROR_INVALID_PASSWORD, (SEC_ERROR_BASE + 101), +"Password entered is invalid. Please pick a different one.") + +ER3(SEC_ERROR_RETRY_OLD_PASSWORD, (SEC_ERROR_BASE + 102), +"Old password entered incorrectly. Please try again.") + +ER3(SEC_ERROR_BAD_NICKNAME, (SEC_ERROR_BASE + 103), +"Certificate nickname already in use.") + +ER3(SEC_ERROR_NOT_FORTEZZA_ISSUER, (SEC_ERROR_BASE + 104), +"Peer FORTEZZA chain has a non-FORTEZZA Certificate.") + +ER3(SEC_ERROR_CANNOT_MOVE_SENSITIVE_KEY, (SEC_ERROR_BASE + 105), +"A sensitive key cannot be moved to the slot where it is needed.") + +ER3(SEC_ERROR_JS_INVALID_MODULE_NAME, (SEC_ERROR_BASE + 106), +"Invalid module name.") + +ER3(SEC_ERROR_JS_INVALID_DLL, (SEC_ERROR_BASE + 107), +"Invalid module path/filename") + +ER3(SEC_ERROR_JS_ADD_MOD_FAILURE, (SEC_ERROR_BASE + 108), +"Unable to add module") + +ER3(SEC_ERROR_JS_DEL_MOD_FAILURE, (SEC_ERROR_BASE + 109), +"Unable to delete module") + +ER3(SEC_ERROR_OLD_KRL, (SEC_ERROR_BASE + 110), +"New KRL is not later than the current one.") + +ER3(SEC_ERROR_CKL_CONFLICT, (SEC_ERROR_BASE + 111), +"New CKL has different issuer than current CKL. Delete current CKL.") + +ER3(SEC_ERROR_CERT_NOT_IN_NAME_SPACE, (SEC_ERROR_BASE + 112), +"The Certifying Authority for this certificate is not permitted to issue a \ +certificate with this name.") + +ER3(SEC_ERROR_KRL_NOT_YET_VALID, (SEC_ERROR_BASE + 113), +"The key revocation list for this certificate is not yet valid.") + +ER3(SEC_ERROR_CRL_NOT_YET_VALID, (SEC_ERROR_BASE + 114), +"The certificate revocation list for this certificate is not yet valid.") + +ER3(SEC_ERROR_UNKNOWN_CERT, (SEC_ERROR_BASE + 115), +"The requested certificate could not be found.") + +ER3(SEC_ERROR_UNKNOWN_SIGNER, (SEC_ERROR_BASE + 116), +"The signer's certificate could not be found.") + +ER3(SEC_ERROR_CERT_BAD_ACCESS_LOCATION, (SEC_ERROR_BASE + 117), +"The location for the certificate status server has invalid format.") + +ER3(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_TYPE, (SEC_ERROR_BASE + 118), +"The OCSP response cannot be fully decoded; it is of an unknown type.") + +ER3(SEC_ERROR_OCSP_BAD_HTTP_RESPONSE, (SEC_ERROR_BASE + 119), +"The OCSP server returned unexpected/invalid HTTP data.") + +ER3(SEC_ERROR_OCSP_MALFORMED_REQUEST, (SEC_ERROR_BASE + 120), +"The OCSP server found the request to be corrupted or improperly formed.") + +ER3(SEC_ERROR_OCSP_SERVER_ERROR, (SEC_ERROR_BASE + 121), +"The OCSP server experienced an internal error.") + +ER3(SEC_ERROR_OCSP_TRY_SERVER_LATER, (SEC_ERROR_BASE + 122), +"The OCSP server suggests trying again later.") + +ER3(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG, (SEC_ERROR_BASE + 123), +"The OCSP server requires a signature on this request.") + +ER3(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST, (SEC_ERROR_BASE + 124), +"The OCSP server has refused this request as unauthorized.") + +ER3(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, (SEC_ERROR_BASE + 125), +"The OCSP server returned an unrecognizable status.") + +ER3(SEC_ERROR_OCSP_UNKNOWN_CERT, (SEC_ERROR_BASE + 126), +"The OCSP server has no status for the certificate.") + +ER3(SEC_ERROR_OCSP_NOT_ENABLED, (SEC_ERROR_BASE + 127), +"You must enable OCSP before performing this operation.") + +ER3(SEC_ERROR_OCSP_NO_DEFAULT_RESPONDER, (SEC_ERROR_BASE + 128), +"You must set the OCSP default responder before performing this operation.") + +ER3(SEC_ERROR_OCSP_MALFORMED_RESPONSE, (SEC_ERROR_BASE + 129), +"The response from the OCSP server was corrupted or improperly formed.") + +ER3(SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE, (SEC_ERROR_BASE + 130), +"The signer of the OCSP response is not authorized to give status for \ +this certificate.") + +ER3(SEC_ERROR_OCSP_FUTURE_RESPONSE, (SEC_ERROR_BASE + 131), +"The OCSP response is not yet valid (contains a date in the future).") + +ER3(SEC_ERROR_OCSP_OLD_RESPONSE, (SEC_ERROR_BASE + 132), +"The OCSP response contains out-of-date information.") + +ER3(SEC_ERROR_DIGEST_NOT_FOUND, (SEC_ERROR_BASE + 133), +"The CMS or PKCS #7 Digest was not found in signed message.") + +ER3(SEC_ERROR_UNSUPPORTED_MESSAGE_TYPE, (SEC_ERROR_BASE + 134), +"The CMS or PKCS #7 Message type is unsupported.") + +ER3(SEC_ERROR_MODULE_STUCK, (SEC_ERROR_BASE + 135), +"PKCS #11 module could not be removed because it is still in use.") + +ER3(SEC_ERROR_BAD_TEMPLATE, (SEC_ERROR_BASE + 136), +"Could not decode ASN.1 data. Specified template was invalid.") + +ER3(SEC_ERROR_CRL_NOT_FOUND, (SEC_ERROR_BASE + 137), +"No matching CRL was found.") + +ER3(SEC_ERROR_REUSED_ISSUER_AND_SERIAL, (SEC_ERROR_BASE + 138), +"You are attempting to import a cert with the same issuer/serial as \ +an existing cert, but that is not the same cert.") + +ER3(SEC_ERROR_BUSY, (SEC_ERROR_BASE + 139), +"NSS could not shutdown. Objects are still in use.") + +ER3(SEC_ERROR_EXTRA_INPUT, (SEC_ERROR_BASE + 140), +"DER-encoded message contained extra usused data.") + +ER3(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE, (SEC_ERROR_BASE + 141), +"Unsupported elliptic curve.") + +ER3(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM, (SEC_ERROR_BASE + 142), +"Unsupported elliptic curve point form.") + +ER3(SEC_ERROR_UNRECOGNIZED_OID, (SEC_ERROR_BASE + 143), +"Unrecognized Object IDentifier.") diff --git a/security/nss/cmd/lib/SSLerrs.h b/security/nss/cmd/lib/SSLerrs.h new file mode 100644 index 000000000..06803b849 --- /dev/null +++ b/security/nss/cmd/lib/SSLerrs.h @@ -0,0 +1,366 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* SSL-specific security error codes */ +/* caller must include "sslerr.h" */ + +ER3(SSL_ERROR_EXPORT_ONLY_SERVER, SSL_ERROR_BASE + 0, +"Unable to communicate securely. Peer does not support high-grade encryption.") + +ER3(SSL_ERROR_US_ONLY_SERVER, SSL_ERROR_BASE + 1, +"Unable to communicate securely. Peer requires high-grade encryption which is not supported.") + +ER3(SSL_ERROR_NO_CYPHER_OVERLAP, SSL_ERROR_BASE + 2, +"Cannot communicate securely with peer: no common encryption algorithm(s).") + +ER3(SSL_ERROR_NO_CERTIFICATE, SSL_ERROR_BASE + 3, +"Unable to find the certificate or key necessary for authentication.") + +ER3(SSL_ERROR_BAD_CERTIFICATE, SSL_ERROR_BASE + 4, +"Unable to communicate securely with peer: peers's certificate was rejected.") + +/* unused (SSL_ERROR_BASE + 5),*/ + +ER3(SSL_ERROR_BAD_CLIENT, SSL_ERROR_BASE + 6, +"The server has encountered bad data from the client.") + +ER3(SSL_ERROR_BAD_SERVER, SSL_ERROR_BASE + 7, +"The client has encountered bad data from the server.") + +ER3(SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE, SSL_ERROR_BASE + 8, +"Unsupported certificate type.") + +ER3(SSL_ERROR_UNSUPPORTED_VERSION, SSL_ERROR_BASE + 9, +"Peer using unsupported version of security protocol.") + +/* unused (SSL_ERROR_BASE + 10),*/ + +ER3(SSL_ERROR_WRONG_CERTIFICATE, SSL_ERROR_BASE + 11, +"Client authentication failed: private key in key database does not match public key in certificate database.") + +ER3(SSL_ERROR_BAD_CERT_DOMAIN, SSL_ERROR_BASE + 12, +"Unable to communicate securely with peer: requested domain name does not match the server's certificate.") + +/* SSL_ERROR_POST_WARNING (SSL_ERROR_BASE + 13), + defined in sslerr.h +*/ + +ER3(SSL_ERROR_SSL2_DISABLED, (SSL_ERROR_BASE + 14), +"Peer only supports SSL version 2, which is locally disabled.") + + +ER3(SSL_ERROR_BAD_MAC_READ, (SSL_ERROR_BASE + 15), +"SSL received a record with an incorrect Message Authentication Code.") + +ER3(SSL_ERROR_BAD_MAC_ALERT, (SSL_ERROR_BASE + 16), +"SSL peer reports incorrect Message Authentication Code.") + +ER3(SSL_ERROR_BAD_CERT_ALERT, (SSL_ERROR_BASE + 17), +"SSL peer cannot verify your certificate.") + +ER3(SSL_ERROR_REVOKED_CERT_ALERT, (SSL_ERROR_BASE + 18), +"SSL peer rejected your certificate as revoked.") + +ER3(SSL_ERROR_EXPIRED_CERT_ALERT, (SSL_ERROR_BASE + 19), +"SSL peer rejected your certificate as expired.") + +ER3(SSL_ERROR_SSL_DISABLED, (SSL_ERROR_BASE + 20), +"Cannot connect: SSL is disabled.") + +ER3(SSL_ERROR_FORTEZZA_PQG, (SSL_ERROR_BASE + 21), +"Cannot connect: SSL peer is in another FORTEZZA domain.") + + +ER3(SSL_ERROR_UNKNOWN_CIPHER_SUITE , (SSL_ERROR_BASE + 22), +"An unknown SSL cipher suite has been requested.") + +ER3(SSL_ERROR_NO_CIPHERS_SUPPORTED , (SSL_ERROR_BASE + 23), +"No cipher suites are present and enabled in this program.") + +ER3(SSL_ERROR_BAD_BLOCK_PADDING , (SSL_ERROR_BASE + 24), +"SSL received a record with bad block padding.") + +ER3(SSL_ERROR_RX_RECORD_TOO_LONG , (SSL_ERROR_BASE + 25), +"SSL received a record that exceeded the maximum permissible length.") + +ER3(SSL_ERROR_TX_RECORD_TOO_LONG , (SSL_ERROR_BASE + 26), +"SSL attempted to send a record that exceeded the maximum permissible length.") + +/* + * Received a malformed (too long or short or invalid content) SSL handshake. + */ +ER3(SSL_ERROR_RX_MALFORMED_HELLO_REQUEST , (SSL_ERROR_BASE + 27), +"SSL received a malformed Hello Request handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CLIENT_HELLO , (SSL_ERROR_BASE + 28), +"SSL received a malformed Client Hello handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_SERVER_HELLO , (SSL_ERROR_BASE + 29), +"SSL received a malformed Server Hello handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CERTIFICATE , (SSL_ERROR_BASE + 30), +"SSL received a malformed Certificate handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_SERVER_KEY_EXCH , (SSL_ERROR_BASE + 31), +"SSL received a malformed Server Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CERT_REQUEST , (SSL_ERROR_BASE + 32), +"SSL received a malformed Certificate Request handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_HELLO_DONE , (SSL_ERROR_BASE + 33), +"SSL received a malformed Server Hello Done handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CERT_VERIFY , (SSL_ERROR_BASE + 34), +"SSL received a malformed Certificate Verify handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_CLIENT_KEY_EXCH , (SSL_ERROR_BASE + 35), +"SSL received a malformed Client Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_MALFORMED_FINISHED , (SSL_ERROR_BASE + 36), +"SSL received a malformed Finished handshake message.") + +/* + * Received a malformed (too long or short) SSL record. + */ +ER3(SSL_ERROR_RX_MALFORMED_CHANGE_CIPHER , (SSL_ERROR_BASE + 37), +"SSL received a malformed Change Cipher Spec record.") + +ER3(SSL_ERROR_RX_MALFORMED_ALERT , (SSL_ERROR_BASE + 38), +"SSL received a malformed Alert record.") + +ER3(SSL_ERROR_RX_MALFORMED_HANDSHAKE , (SSL_ERROR_BASE + 39), +"SSL received a malformed Handshake record.") + +ER3(SSL_ERROR_RX_MALFORMED_APPLICATION_DATA , (SSL_ERROR_BASE + 40), +"SSL received a malformed Application Data record.") + +/* + * Received an SSL handshake that was inappropriate for the state we're in. + * E.g. Server received message from server, or wrong state in state machine. + */ +ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_REQUEST , (SSL_ERROR_BASE + 41), +"SSL received an unexpected Hello Request handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_HELLO , (SSL_ERROR_BASE + 42), +"SSL received an unexpected Client Hello handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_HELLO , (SSL_ERROR_BASE + 43), +"SSL received an unexpected Server Hello handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CERTIFICATE , (SSL_ERROR_BASE + 44), +"SSL received an unexpected Certificate handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_SERVER_KEY_EXCH , (SSL_ERROR_BASE + 45), +"SSL received an unexpected Server Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CERT_REQUEST , (SSL_ERROR_BASE + 46), +"SSL received an unexpected Certificate Request handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_HELLO_DONE , (SSL_ERROR_BASE + 47), +"SSL received an unexpected Server Hello Done handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CERT_VERIFY , (SSL_ERROR_BASE + 48), +"SSL received an unexpected Certificate Verify handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_CLIENT_KEY_EXCH , (SSL_ERROR_BASE + 49), +"SSL received an unexpected Cllient Key Exchange handshake message.") + +ER3(SSL_ERROR_RX_UNEXPECTED_FINISHED , (SSL_ERROR_BASE + 50), +"SSL received an unexpected Finished handshake message.") + +/* + * Received an SSL record that was inappropriate for the state we're in. + */ +ER3(SSL_ERROR_RX_UNEXPECTED_CHANGE_CIPHER , (SSL_ERROR_BASE + 51), +"SSL received an unexpected Change Cipher Spec record.") + +ER3(SSL_ERROR_RX_UNEXPECTED_ALERT , (SSL_ERROR_BASE + 52), +"SSL received an unexpected Alert record.") + +ER3(SSL_ERROR_RX_UNEXPECTED_HANDSHAKE , (SSL_ERROR_BASE + 53), +"SSL received an unexpected Handshake record.") + +ER3(SSL_ERROR_RX_UNEXPECTED_APPLICATION_DATA, (SSL_ERROR_BASE + 54), +"SSL received an unexpected Application Data record.") + +/* + * Received record/message with unknown discriminant. + */ +ER3(SSL_ERROR_RX_UNKNOWN_RECORD_TYPE , (SSL_ERROR_BASE + 55), +"SSL received a record with an unknown content type.") + +ER3(SSL_ERROR_RX_UNKNOWN_HANDSHAKE , (SSL_ERROR_BASE + 56), +"SSL received a handshake message with an unknown message type.") + +ER3(SSL_ERROR_RX_UNKNOWN_ALERT , (SSL_ERROR_BASE + 57), +"SSL received an alert record with an unknown alert description.") + +/* + * Received an alert reporting what we did wrong. (more alerts above) + */ +ER3(SSL_ERROR_CLOSE_NOTIFY_ALERT , (SSL_ERROR_BASE + 58), +"SSL peer has closed this connection.") + +ER3(SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT , (SSL_ERROR_BASE + 59), +"SSL peer was not expecting a handshake message it received.") + +ER3(SSL_ERROR_DECOMPRESSION_FAILURE_ALERT , (SSL_ERROR_BASE + 60), +"SSL peer was unable to succesfully decompress an SSL record it received.") + +ER3(SSL_ERROR_HANDSHAKE_FAILURE_ALERT , (SSL_ERROR_BASE + 61), +"SSL peer was unable to negotiate an acceptable set of security parameters.") + +ER3(SSL_ERROR_ILLEGAL_PARAMETER_ALERT , (SSL_ERROR_BASE + 62), +"SSL peer rejected a handshake message for unacceptable content.") + +ER3(SSL_ERROR_UNSUPPORTED_CERT_ALERT , (SSL_ERROR_BASE + 63), +"SSL peer does not support certificates of the type it received.") + +ER3(SSL_ERROR_CERTIFICATE_UNKNOWN_ALERT , (SSL_ERROR_BASE + 64), +"SSL peer had some unspecified issue with the certificate it received.") + + +ER3(SSL_ERROR_GENERATE_RANDOM_FAILURE , (SSL_ERROR_BASE + 65), +"SSL experienced a failure of its random number generator.") + +ER3(SSL_ERROR_SIGN_HASHES_FAILURE , (SSL_ERROR_BASE + 66), +"Unable to digitally sign data required to verify your certificate.") + +ER3(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE , (SSL_ERROR_BASE + 67), +"SSL was unable to extract the public key from the peer's certificate.") + +ER3(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE , (SSL_ERROR_BASE + 68), +"Unspecified failure while processing SSL Server Key Exchange handshake.") + +ER3(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE , (SSL_ERROR_BASE + 69), +"Unspecified failure while processing SSL Client Key Exchange handshake.") + +ER3(SSL_ERROR_ENCRYPTION_FAILURE , (SSL_ERROR_BASE + 70), +"Bulk data encryption algorithm failed in selected cipher suite.") + +ER3(SSL_ERROR_DECRYPTION_FAILURE , (SSL_ERROR_BASE + 71), +"Bulk data decryption algorithm failed in selected cipher suite.") + +ER3(SSL_ERROR_SOCKET_WRITE_FAILURE , (SSL_ERROR_BASE + 72), +"Attempt to write encrypted data to underlying socket failed.") + +ER3(SSL_ERROR_MD5_DIGEST_FAILURE , (SSL_ERROR_BASE + 73), +"MD5 digest function failed.") + +ER3(SSL_ERROR_SHA_DIGEST_FAILURE , (SSL_ERROR_BASE + 74), +"SHA-1 digest function failed.") + +ER3(SSL_ERROR_MAC_COMPUTATION_FAILURE , (SSL_ERROR_BASE + 75), +"MAC computation failed.") + +ER3(SSL_ERROR_SYM_KEY_CONTEXT_FAILURE , (SSL_ERROR_BASE + 76), +"Failure to create Symmetric Key context.") + +ER3(SSL_ERROR_SYM_KEY_UNWRAP_FAILURE , (SSL_ERROR_BASE + 77), +"Failure to unwrap the Symmetric key in Client Key Exchange message.") + +ER3(SSL_ERROR_PUB_KEY_SIZE_LIMIT_EXCEEDED , (SSL_ERROR_BASE + 78), +"SSL Server attempted to use domestic-grade public key with export cipher suite.") + +ER3(SSL_ERROR_IV_PARAM_FAILURE , (SSL_ERROR_BASE + 79), +"PKCS11 code failed to translate an IV into a param.") + +ER3(SSL_ERROR_INIT_CIPHER_SUITE_FAILURE , (SSL_ERROR_BASE + 80), +"Failed to initialize the selected cipher suite.") + +ER3(SSL_ERROR_SESSION_KEY_GEN_FAILURE , (SSL_ERROR_BASE + 81), +"Client failed to generate session keys for SSL session.") + +ER3(SSL_ERROR_NO_SERVER_KEY_FOR_ALG , (SSL_ERROR_BASE + 82), +"Server has no key for the attempted key exchange algorithm.") + +ER3(SSL_ERROR_TOKEN_INSERTION_REMOVAL , (SSL_ERROR_BASE + 83), +"PKCS#11 token was inserted or removed while operation was in progress.") + +ER3(SSL_ERROR_TOKEN_SLOT_NOT_FOUND , (SSL_ERROR_BASE + 84), +"No PKCS#11 token could be found to do a required operation.") + +ER3(SSL_ERROR_NO_COMPRESSION_OVERLAP , (SSL_ERROR_BASE + 85), +"Cannot communicate securely with peer: no common compression algorithm(s).") + +ER3(SSL_ERROR_HANDSHAKE_NOT_COMPLETED , (SSL_ERROR_BASE + 86), +"Cannot initiate another SSL handshake until current handshake is complete.") + +ER3(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE , (SSL_ERROR_BASE + 87), +"Received incorrect handshakes hash values from peer.") + +ER3(SSL_ERROR_CERT_KEA_MISMATCH , (SSL_ERROR_BASE + 88), +"The certificate provided cannot be used with the selected key exchange algorithm.") + +ER3(SSL_ERROR_NO_TRUSTED_SSL_CLIENT_CA , (SSL_ERROR_BASE + 89), +"No certificate authority is trusted for SSL client authentication.") + +ER3(SSL_ERROR_SESSION_NOT_FOUND , (SSL_ERROR_BASE + 90), +"Client's SSL session ID not found in server's session cache.") + +ER3(SSL_ERROR_DECRYPTION_FAILED_ALERT , (SSL_ERROR_BASE + 91), +"Peer was unable to decrypt an SSL record it received.") + +ER3(SSL_ERROR_RECORD_OVERFLOW_ALERT , (SSL_ERROR_BASE + 92), +"Peer received an SSL record that was longer than is permitted.") + +ER3(SSL_ERROR_UNKNOWN_CA_ALERT , (SSL_ERROR_BASE + 93), +"Peer does not recognize and trust the CA that issued your certificate.") + +ER3(SSL_ERROR_ACCESS_DENIED_ALERT , (SSL_ERROR_BASE + 94), +"Peer received a valid certificate, but access was denied.") + +ER3(SSL_ERROR_DECODE_ERROR_ALERT , (SSL_ERROR_BASE + 95), +"Peer could not decode an SSL handshake message.") + +ER3(SSL_ERROR_DECRYPT_ERROR_ALERT , (SSL_ERROR_BASE + 96), +"Peer reports failure of signature verification or key exchange.") + +ER3(SSL_ERROR_EXPORT_RESTRICTION_ALERT , (SSL_ERROR_BASE + 97), +"Peer reports negotiation not in compliance with export regulations.") + +ER3(SSL_ERROR_PROTOCOL_VERSION_ALERT , (SSL_ERROR_BASE + 98), +"Peer reports incompatible or unsupported protocol version.") + +ER3(SSL_ERROR_INSUFFICIENT_SECURITY_ALERT , (SSL_ERROR_BASE + 99), +"Server requires ciphers more secure than those supported by client.") + +ER3(SSL_ERROR_INTERNAL_ERROR_ALERT , (SSL_ERROR_BASE + 100), +"Peer reports it experienced an internal error.") + +ER3(SSL_ERROR_USER_CANCELED_ALERT , (SSL_ERROR_BASE + 101), +"Peer user canceled handshake.") + +ER3(SSL_ERROR_NO_RENEGOTIATION_ALERT , (SSL_ERROR_BASE + 102), +"Peer does not permit renegotiation of SSL security parameters.") + diff --git a/security/nss/cmd/lib/berparse.c b/security/nss/cmd/lib/berparse.c new file mode 100644 index 000000000..c040ab2b1 --- /dev/null +++ b/security/nss/cmd/lib/berparse.c @@ -0,0 +1,404 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "secutil.h" + +typedef enum { + tagDone, lengthDone, leafDone, compositeDone, + notDone, + parseError, parseComplete +} ParseState; + +typedef unsigned char Byte; +typedef void (*ParseProc)(BERParse *h, unsigned char **buf, int *len); +typedef struct { + SECArb arb; + int pos; /* length from global start to item start */ + SECArb *parent; +} ParseStackElem; + +struct BERParseStr { + PRArenaPool *his; + PRArenaPool *mine; + ParseProc proc; + int stackDepth; + ParseStackElem *stackPtr; + ParseStackElem *stack; + int pending; /* bytes remaining to complete this part */ + int pos; /* running length of consumed characters */ + ParseState state; + PRBool keepLeaves; + PRBool derOnly; + BERFilterProc filter; + void *filterArg; + BERNotifyProc before; + void *beforeArg; + BERNotifyProc after; + void *afterArg; +}; + +#define UNKNOWN -1 + +static unsigned char NextChar(BERParse *h, unsigned char **buf, int *len) +{ + unsigned char c = *(*buf)++; + (*len)--; + h->pos++; + if (h->filter) + (*h->filter)(h->filterArg, &c, 1); + return c; +} + +static void ParseTag(BERParse *h, unsigned char **buf, int *len) +{ + SECArb* arb = &(h->stackPtr->arb); + arb->tag = NextChar(h, buf, len); + + PORT_Assert(h->state == notDone); + + /* + * NOTE: This does not handle the high-tag-number form + */ + if ((arb->tag & DER_HIGH_TAG_NUMBER) == DER_HIGH_TAG_NUMBER) { + PORT_SetError(SEC_ERROR_BAD_DER); + h->state = parseError; + return; + } + + h->pending = UNKNOWN; + arb->length = UNKNOWN; + if (arb->tag & DER_CONSTRUCTED) { + arb->body.cons.numSubs = 0; + arb->body.cons.subs = NULL; + } else { + arb->body.item.len = UNKNOWN; + arb->body.item.data = NULL; + } + + h->state = tagDone; +} + +static void ParseLength(BERParse *h, unsigned char **buf, int *len) +{ + Byte b; + SECArb *arb = &(h->stackPtr->arb); + + PORT_Assert(h->state == notDone); + + if (h->pending == UNKNOWN) { + b = NextChar(h, buf, len); + if ((b & 0x80) == 0) { /* short form */ + arb->length = b; + /* + * if the tag and the length are both zero bytes, then this + * should be the marker showing end of list for the + * indefinite length composite + */ + if (arb->length == 0 && arb->tag == 0) + h->state = compositeDone; + else + h->state = lengthDone; + return; + } + + h->pending = b & 0x7f; + /* 0 implies this is an indefinite length */ + if (h->pending > 4) { + PORT_SetError(SEC_ERROR_BAD_DER); + h->state = parseError; + return; + } + arb->length = 0; + } + + while ((*len > 0) && (h->pending > 0)) { + b = NextChar(h, buf, len); + arb->length = (arb->length << 8) + b; + h->pending--; + } + if (h->pending == 0) { + if (h->derOnly && (arb->length == 0)) + h->state = parseError; + else + h->state = lengthDone; + } + return; +} + +static void ParseLeaf(BERParse *h, unsigned char **buf, int *len) +{ + int count; + SECArb *arb = &(h->stackPtr->arb); + + PORT_Assert(h->state == notDone); + PORT_Assert(h->pending >= 0); + + if (*len < h->pending) + count = *len; + else + count = h->pending; + + if (h->keepLeaves) + memcpy(arb->body.item.data + arb->body.item.len, *buf, count); + if (h->filter) + (*h->filter)(h->filterArg, *buf, count); + *buf += count; + *len -= count; + arb->body.item.len += count; + h->pending -= count; + h->pos += count; + if (h->pending == 0) { + h->state = leafDone; + } + return; +} + +static void CreateArbNode(BERParse *h) +{ + SECArb *arb = PORT_ArenaAlloc(h->his, sizeof(SECArb)); + + *arb = h->stackPtr->arb; + + /* + * Special case closing the root + */ + if (h->stackPtr == h->stack) { + PORT_Assert(arb->tag & DER_CONSTRUCTED); + h->state = parseComplete; + } else { + SECArb *parent = h->stackPtr->parent; + parent->body.cons.subs = DS_ArenaGrow( + h->his, parent->body.cons.subs, + (parent->body.cons.numSubs) * sizeof(SECArb*), + (parent->body.cons.numSubs + 1) * sizeof(SECArb*)); + parent->body.cons.subs[parent->body.cons.numSubs] = arb; + parent->body.cons.numSubs++; + h->proc = ParseTag; + h->state = notDone; + h->pending = UNKNOWN; + } + if (h->after) + (*h->after)(h->afterArg, arb, h->stackPtr - h->stack, PR_FALSE); +} + +SECStatus BER_ParseSome(BERParse *h, unsigned char *buf, int len) +{ + if (h->state == parseError) return PR_TRUE; + + while (len) { + (*h->proc)(h, &buf, &len); + if (h->state == parseComplete) { + PORT_SetError(SEC_ERROR_BAD_DER); + h->state = parseError; + return PR_TRUE; + } + if (h->state == parseError) return PR_TRUE; + PORT_Assert(h->state != parseComplete); + + if (h->state <= compositeDone) { + if (h->proc == ParseTag) { + PORT_Assert(h->state == tagDone); + h->proc = ParseLength; + h->state = notDone; + } else if (h->proc == ParseLength) { + SECArb *arb = &(h->stackPtr->arb); + PORT_Assert(h->state == lengthDone || h->state == compositeDone); + + if (h->before) + (*h->before)(h->beforeArg, arb, + h->stackPtr - h->stack, PR_TRUE); + + /* + * Check to see if this is the end of an indefinite + * length composite + */ + if (h->state == compositeDone) { + SECArb *parent = h->stackPtr->parent; + PORT_Assert(parent); + PORT_Assert(parent->tag & DER_CONSTRUCTED); + if (parent->length != 0) { + PORT_SetError(SEC_ERROR_BAD_DER); + h->state = parseError; + return PR_TRUE; + } + /* + * NOTE: This does not check for an indefinite length + * composite being contained inside a definite length + * composite. It is not clear that is legal. + */ + h->stackPtr--; + CreateArbNode(h); + } else { + h->stackPtr->pos = h->pos; + + + if (arb->tag & DER_CONSTRUCTED) { + SECArb *parent; + /* + * Make sure there is room on the stack before we + * stick anything else there. + */ + PORT_Assert(h->stackPtr - h->stack < h->stackDepth); + if (h->stackPtr - h->stack == h->stackDepth - 1) { + int newDepth = h->stackDepth * 2; + h->stack = DS_ArenaGrow(h->mine, h->stack, + sizeof(ParseStackElem) * h->stackDepth, + sizeof(ParseStackElem) * newDepth); + h->stackPtr = h->stack + h->stackDepth + 1; + h->stackDepth = newDepth; + } + parent = &(h->stackPtr->arb); + h->stackPtr++; + h->stackPtr->parent = parent; + h->proc = ParseTag; + h->state = notDone; + h->pending = UNKNOWN; + } else { + if (arb->length < 0) { + PORT_SetError(SEC_ERROR_BAD_DER); + h->state = parseError; + return PR_TRUE; + } + arb->body.item.len = 0; + if (arb->length > 0 && h->keepLeaves) { + arb->body.item.data = + PORT_ArenaAlloc(h->his, arb->length); + } else { + arb->body.item.data = NULL; + } + h->proc = ParseLeaf; + h->state = notDone; + h->pending = arb->length; + } + } + } else { + ParseStackElem *parent; + PORT_Assert(h->state = leafDone); + PORT_Assert(h->proc == ParseLeaf); + + for (;;) { + CreateArbNode(h); + if (h->stackPtr == h->stack) + break; + parent = (h->stackPtr - 1); + PORT_Assert(parent->arb.tag & DER_CONSTRUCTED); + if (parent->arb.length == 0) /* need explicit end */ + break; + if (parent->pos + parent->arb.length > h->pos) + break; + if (parent->pos + parent->arb.length < h->pos) { + PORT_SetError(SEC_ERROR_BAD_DER); + h->state = parseError; + return PR_TRUE; + } + h->stackPtr = parent; + } + } + + } + } + return PR_FALSE; +} +BERParse *BER_ParseInit(PRArenaPool *arena, PRBool derOnly) +{ + BERParse *h; + PRArenaPool *temp = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (temp == NULL) { + PORT_SetError(SEC_ERROR_NO_MEMORY); + return NULL; + } + h = PORT_ArenaAlloc(temp, sizeof(BERParse)); + if (h == NULL) { + PORT_FreeArena(temp, PR_FALSE); + PORT_SetError(SEC_ERROR_NO_MEMORY); + return NULL; + } + h->his = arena; + h->mine = temp; + h->proc = ParseTag; + h->stackDepth = 20; + h->stack = PORT_ArenaZAlloc(h->mine, + sizeof(ParseStackElem) * h->stackDepth); + h->stackPtr = h->stack; + h->state = notDone; + h->pos = 0; + h->keepLeaves = PR_TRUE; + h->before = NULL; + h->after = NULL; + h->filter = NULL; + h->derOnly = derOnly; + return h; +} + +SECArb *BER_ParseFini(BERParse *h) +{ + PRArenaPool *myArena = h->mine; + SECArb *arb; + + if (h->state != parseComplete) { + arb = NULL; + } else { + arb = PORT_ArenaAlloc(h->his, sizeof(SECArb)); + *arb = h->stackPtr->arb; + } + + PORT_FreeArena(myArena, PR_FALSE); + + return arb; +} + + +void BER_SetFilter(BERParse *h, BERFilterProc proc, void *instance) +{ + h->filter = proc; + h->filterArg = instance; +} + +void BER_SetLeafStorage(BERParse *h, PRBool keep) +{ + h->keepLeaves = keep; +} + +void BER_SetNotifyProc(BERParse *h, BERNotifyProc proc, void *instance, + PRBool beforeData) +{ + if (beforeData) { + h->before = proc; + h->beforeArg = instance; + } else { + h->after = proc; + h->afterArg = instance; + } +} + + + diff --git a/security/nss/cmd/lib/config.mk b/security/nss/cmd/lib/config.mk new file mode 100644 index 000000000..0a00dc61e --- /dev/null +++ b/security/nss/cmd/lib/config.mk @@ -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. +# + +# +# Override TARGETS variable so that only static libraries +# are specifed as dependencies within rules.mk. +# + +TARGETS = $(LIBRARY) +SHARED_LIBRARY = +IMPORT_LIBRARY = +PROGRAM = + diff --git a/security/nss/cmd/lib/derprint.c b/security/nss/cmd/lib/derprint.c new file mode 100644 index 000000000..7f699dec4 --- /dev/null +++ b/security/nss/cmd/lib/derprint.c @@ -0,0 +1,619 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "secutil.h" +#include "secoid.h" + +#ifdef __sun +extern int fprintf(FILE *strm, const char *format, .../* args */); +extern int fflush(FILE *stream); +#endif + +#define RIGHT_MARGIN 24 +/*#define RAW_BYTES 1 */ + +static int prettyColumn = 0; + +static int +getInteger256(unsigned char *data, unsigned int nb) +{ + int val; + + switch (nb) { + case 1: + val = data[0]; + break; + case 2: + val = (data[0] << 8) | data[1]; + break; + case 3: + val = (data[0] << 16) | (data[1] << 8) | data[2]; + break; + case 4: + val = (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3]; + break; + default: + PORT_SetError(SEC_ERROR_BAD_DER); + return -1; + } + + return val; +} + +static int +prettyNewline(FILE *out) +{ + int rv; + + if (prettyColumn != -1) { + rv = fprintf(out, "\n"); + prettyColumn = -1; + if (rv < 0) { + PORT_SetError(SEC_ERROR_IO); + return rv; + } + } + return 0; +} + +static int +prettyIndent(FILE *out, unsigned level) +{ + unsigned int i; + int rv; + + if (prettyColumn == -1) { + prettyColumn = level; + for (i = 0; i < level; i++) { + rv = fprintf(out, " "); + if (rv < 0) { + PORT_SetError(SEC_ERROR_IO); + return rv; + } + } + } + + return 0; +} + +static int +prettyPrintByte(FILE *out, unsigned char item, unsigned int level) +{ + int rv; + + rv = prettyIndent(out, level); + if (rv < 0) + return rv; + + rv = fprintf(out, "%02x ", item); + if (rv < 0) { + PORT_SetError(SEC_ERROR_IO); + return rv; + } + + prettyColumn++; + if (prettyColumn >= RIGHT_MARGIN) { + return prettyNewline(out); + } + + return 0; +} + +static int +prettyPrintLeaf(FILE *out, unsigned char *data, + unsigned int len, unsigned int lv) +{ + unsigned int i; + int rv; + + for (i = 0; i < len; i++) { + rv = prettyPrintByte(out, *data++, lv); + if (rv < 0) + return rv; + } + return prettyNewline(out); +} + +static int +prettyPrintStringStart(FILE *out, unsigned char *str, + unsigned int len, unsigned int level) +{ +#define BUF_SIZE 100 + unsigned char buf[BUF_SIZE]; + int rv; + + if (len >= BUF_SIZE) + len = BUF_SIZE - 1; + + rv = prettyNewline(out); + if (rv < 0) + return rv; + + rv = prettyIndent(out, level); + if (rv < 0) + return rv; + + memcpy(buf, str, len); + buf[len] = '\000'; + + rv = fprintf(out, "\"%s\"", buf); + if (rv < 0) { + PORT_SetError(SEC_ERROR_IO); + return rv; + } + + return 0; +#undef BUF_SIZE +} + +static int +prettyPrintString(FILE *out, unsigned char *str, + unsigned int len, unsigned int level, PRBool raw) +{ + int rv; + + rv = prettyPrintStringStart(out, str, len, level); + if (rv < 0) + return rv; + + rv = prettyNewline(out); + if (rv < 0) + return rv; + + if (raw) { + rv = prettyPrintLeaf(out, str, len, level); + if (rv < 0) + return rv; + } + + return 0; +} + +static int +prettyPrintTime(FILE *out, unsigned char *str, + unsigned int len, unsigned int level, PRBool raw, PRBool utc) +{ + SECItem time_item; + int rv; + + rv = prettyPrintStringStart(out, str, len, level); + if (rv < 0) + return rv; + + time_item.data = str; + time_item.len = len; + + rv = fprintf(out, " ("); + if (rv < 0) { + PORT_SetError(SEC_ERROR_IO); + return rv; + } + + if (utc) + SECU_PrintUTCTime(out, &time_item, NULL, 0); + else + SECU_PrintGeneralizedTime(out, &time_item, NULL, 0); + + rv = fprintf(out, ")"); + if (rv < 0) { + PORT_SetError(SEC_ERROR_IO); + return rv; + } + + rv = prettyNewline(out); + if (rv < 0) + return rv; + + if (raw) { + rv = prettyPrintLeaf(out, str, len, level); + if (rv < 0) + return rv; + } + + return 0; +} + +static int +prettyPrintObjectID(FILE *out, unsigned char *data, + unsigned int len, unsigned int level, PRBool raw) +{ + SECOidData *oiddata; + SECItem oiditem; + unsigned int i; + unsigned long val; + int rv; + + + /* + * First print the Object Id in numeric format + */ + + rv = prettyIndent(out, level); + if (rv < 0) + return rv; + + val = data[0]; + i = val % 40; + val = val / 40; + rv = fprintf(out, "%lu %u ", val, i); + if (rv < 0) { + PORT_SetError(SEC_ERROR_IO); + return rv; + } + + val = 0; + for (i = 1; i < len; ++i) { + unsigned long j; + + j = data[i]; + val = (val << 7) | (j & 0x7f); + if (j & 0x80) + continue; + rv = fprintf(out, "%lu ", val); + if (rv < 0) { + PORT_SetError(SEC_ERROR_IO); + return rv; + } + val = 0; + } + + /* + * Now try to look it up and print a symbolic version. + */ + oiditem.data = data; + oiditem.len = len; + oiddata = SECOID_FindOID(&oiditem); + if (oiddata != NULL) { + i = PORT_Strlen(oiddata->desc); + if ((prettyColumn + 1 + (i / 3)) > RIGHT_MARGIN) { + rv = prettyNewline(out); + if (rv < 0) + return rv; + } + + rv = prettyIndent(out, level); + if (rv < 0) + return rv; + + rv = fprintf(out, "(%s)", oiddata->desc); + if (rv < 0) { + PORT_SetError(SEC_ERROR_IO); + return rv; + } + } + + /* + * Finally, on a new line, print the raw bytes (if requested). + */ + if (raw) { + rv = prettyNewline(out); + if (rv < 0) { + PORT_SetError(SEC_ERROR_IO); + return rv; + } + + for (i = 0; i < len; i++) { + rv = prettyPrintByte(out, *data++, level); + if (rv < 0) + return rv; + } + } + + return prettyNewline(out); +} + +static char *prettyTagType [32] = { + "End of Contents", + "Boolean", + "Integer", + "Bit String", + "Octet String", + "NULL", + "Object Identifier", + "0x07", + "0x08", + "0x09", + "Enumerated", + "0x0B", + "UTF8 String", + "0x0D", + "0x0E", + "0x0F", + "Sequence", + "Set", + "0x12", + "Printable String", + "T61 String", + "0x15", + "IA5 String", + "UTC Time", + "Generalized Time", + "0x19", + "Visible String", + "0x1B", + "Universal String", + "0x1D", + "BMP String", + "High-Tag-Number" +}; + +static int +prettyPrintTag(FILE *out, unsigned char *src, unsigned char *end, + unsigned char *codep, unsigned int level, PRBool raw) +{ + int rv; + unsigned char code, tagnum; + + if (src >= end) { + PORT_SetError(SEC_ERROR_BAD_DER); + return -1; + } + + code = *src; + tagnum = code & SEC_ASN1_TAGNUM_MASK; + + /* + * NOTE: This code does not (yet) handle the high-tag-number form! + */ + if (tagnum == SEC_ASN1_HIGH_TAG_NUMBER) { + PORT_SetError(SEC_ERROR_BAD_DER); + return -1; + } + + if (raw) + rv = prettyPrintByte(out, code, level); + else + rv = prettyIndent(out, level); + + if (rv < 0) + return rv; + + if (code & SEC_ASN1_CONSTRUCTED) { + rv = fprintf(out, "C-"); + if (rv < 0) { + PORT_SetError(SEC_ERROR_IO); + return rv; + } + } + + switch (code & SEC_ASN1_CLASS_MASK) { + case SEC_ASN1_UNIVERSAL: + rv = fprintf(out, "%s ", prettyTagType[tagnum]); + break; + case SEC_ASN1_APPLICATION: + rv = fprintf(out, "Application: %d ", tagnum); + break; + case SEC_ASN1_CONTEXT_SPECIFIC: + rv = fprintf(out, "[%d] ", tagnum); + break; + case SEC_ASN1_PRIVATE: + rv = fprintf(out, "Private: %d ", tagnum); + break; + } + + if (rv < 0) { + PORT_SetError(SEC_ERROR_IO); + return rv; + } + + *codep = code; + + return 1; +} + +static int +prettyPrintLength(FILE *out, unsigned char *data, unsigned char *end, + int *lenp, PRBool *indefinitep, unsigned int lv, PRBool raw) +{ + unsigned char lbyte; + int lenLen; + int rv; + + if (data >= end) { + PORT_SetError(SEC_ERROR_BAD_DER); + return -1; + } + + rv = fprintf(out, " "); + if (rv < 0) { + PORT_SetError(SEC_ERROR_IO); + return rv; + } + + *indefinitep = PR_FALSE; + + lbyte = *data++; + if (lbyte >= 0x80) { + /* Multibyte length */ + unsigned nb = (unsigned) (lbyte & 0x7f); + if (nb > 4) { + PORT_SetError(SEC_ERROR_BAD_DER); + return -1; + } + if (nb > 0) { + int il; + + if ((data + nb) > end) { + PORT_SetError(SEC_ERROR_BAD_DER); + return -1; + } + il = getInteger256(data, nb); + if (il < 0) return -1; + *lenp = (unsigned) il; + } else { + *lenp = 0; + *indefinitep = PR_TRUE; + } + lenLen = nb + 1; + if (raw) { + int i; + + rv = prettyPrintByte(out, lbyte, lv); + if (rv < 0) + return rv; + for (i = 0; i < nb; i++) { + rv = prettyPrintByte(out, data[i], lv); + if (rv < 0) + return rv; + } + } + } else { + *lenp = lbyte; + lenLen = 1; + if (raw) { + rv = prettyPrintByte(out, lbyte, lv); + if (rv < 0) + return rv; + } + } + if (*indefinitep) + rv = fprintf(out, "(indefinite)\n"); + else + rv = fprintf(out, "(%d)\n", *lenp); + if (rv < 0) { + PORT_SetError(SEC_ERROR_IO); + return rv; + } + + prettyColumn = -1; + return lenLen; +} + +static int +prettyPrintItem(FILE *out, unsigned char *data, unsigned char *end, + unsigned int lv, PRBool raw) +{ + int slen; + int lenLen; + unsigned char *orig = data; + int rv; + + while (data < end) { + unsigned char code; + PRBool indefinite; + + slen = prettyPrintTag(out, data, end, &code, lv, raw); + if (slen < 0) + return slen; + data += slen; + + lenLen = prettyPrintLength(out, data, end, &slen, &indefinite, lv, raw); + if (lenLen < 0) + return lenLen; + data += lenLen; + + /* + * Just quit now if slen more bytes puts us off the end. + */ + if ((data + slen) > end) { + PORT_SetError(SEC_ERROR_BAD_DER); + return -1; + } + + if (code & SEC_ASN1_CONSTRUCTED) { + if (slen > 0 || indefinite) { + slen = prettyPrintItem(out, data, + slen == 0 ? end : data + slen, + lv+1, raw); + if (slen < 0) + return slen; + data += slen; + } + } else if (code == 0) { + if (slen != 0 || lenLen != 1) { + PORT_SetError(SEC_ERROR_BAD_DER); + return -1; + } + break; + } else { + switch (code) { + case SEC_ASN1_PRINTABLE_STRING: + case SEC_ASN1_IA5_STRING: + case SEC_ASN1_VISIBLE_STRING: + rv = prettyPrintString(out, data, slen, lv+1, raw); + if (rv < 0) + return rv; + break; + case SEC_ASN1_UTC_TIME: + rv = prettyPrintTime(out, data, slen, lv+1, raw, PR_TRUE); + if (rv < 0) + return rv; + break; + case SEC_ASN1_GENERALIZED_TIME: + rv = prettyPrintTime(out, data, slen, lv+1, raw, PR_FALSE); + if (rv < 0) + return rv; + break; + case SEC_ASN1_OBJECT_ID: + rv = prettyPrintObjectID(out, data, slen, lv+1, raw); + if (rv < 0) + return rv; + break; + case SEC_ASN1_BOOLEAN: /* could do nicer job */ + case SEC_ASN1_INTEGER: /* could do nicer job */ + case SEC_ASN1_BIT_STRING: /* could do nicer job */ + case SEC_ASN1_OCTET_STRING: + case SEC_ASN1_NULL: + case SEC_ASN1_ENUMERATED: /* could do nicer job, as INTEGER */ + case SEC_ASN1_UTF8_STRING: + case SEC_ASN1_T61_STRING: /* print as printable string? */ + case SEC_ASN1_UNIVERSAL_STRING: + case SEC_ASN1_BMP_STRING: + default: + rv = prettyPrintLeaf(out, data, slen, lv+1); + if (rv < 0) + return rv; + break; + } + data += slen; + } + } + + rv = prettyNewline(out); + if (rv < 0) + return rv; + + return data - orig; +} + +SECStatus +DER_PrettyPrint(FILE *out, SECItem *it, PRBool raw) +{ + int rv; + + prettyColumn = -1; + + rv = prettyPrintItem(out, it->data, it->data + it->len, 0, raw); + if (rv < 0) + return SECFailure; + return SECSuccess; +} diff --git a/security/nss/cmd/lib/ffs.c b/security/nss/cmd/lib/ffs.c new file mode 100644 index 000000000..3fce2c7c2 --- /dev/null +++ b/security/nss/cmd/lib/ffs.c @@ -0,0 +1,48 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 XP_PC + +int ffs( unsigned int i) +{ + int rv = 1; + + if (!i) return 0; + + while (!(i & 1)) { + i >>= 1; + ++rv; + } + + return rv; +} +#endif diff --git a/security/nss/cmd/lib/makefile.win b/security/nss/cmd/lib/makefile.win new file mode 100644 index 000000000..92081a2f8 --- /dev/null +++ b/security/nss/cmd/lib/makefile.win @@ -0,0 +1,66 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 <manifest.mn> + +include <$(DEPTH)\config\config.mak> + +# include files are aought in LINCS and INCS. +# LINCS are generated from REQUIRES in manigest.mn +INCS = $(INCS) \ + -I..\include \ + -I..\..\lib\cert \ + $(NULL) + +IGNORE_ME = \ + -I$(DEPTH)\dist\public\security \ + -I$(DEPTH)\dist\public\nspr \ + -I$(DEPTH)\cmd\winfe \ + $(NULL) + +LCFLAGS = -DUSE_SSL -DEXPORT_VERSION + +PDBFILE = $(LIBNAME).pdb + +# work around a bug in rules.mak +LIBRARY_SUFFIX = $(MOZ_BITS) + +include <$(DEPTH)\config\rules.mak> + +install:: $(LIBRARY) +# $(MAKE_INSTALL) $(LIBRARY) $(DIST)\lib + + +symbols:: + @echo "LIBRARY_NAME is $(LIBRARY_NAME)" + @echo "LIBRARY is $(LIBRARY)" diff --git a/security/nss/cmd/lib/manifest.mn b/security/nss/cmd/lib/manifest.mn new file mode 100644 index 000000000..c68285252 --- /dev/null +++ b/security/nss/cmd/lib/manifest.mn @@ -0,0 +1,53 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +LIBRARY_NAME = sectool + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = seccmd + +DEFINES = -DNSPR20 + +EXPORTS = secutil.h \ + $(NULL) + +CSRCS = secutil.c \ + secpwd.c \ + derprint.c \ + secerror.c \ + ffs.c \ + $(NULL) + +REQUIRES = nss nspr dbm + diff --git a/security/nss/cmd/lib/seccnames.c b/security/nss/cmd/lib/seccnames.c new file mode 100644 index 000000000..a1857dc0e --- /dev/null +++ b/security/nss/cmd/lib/seccnames.c @@ -0,0 +1,204 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ +/* +** secutil.c - various functions used by security stuff +** +*/ + +#include "prtypes.h" +#include "prtime.h" +#include "prlong.h" +#include "prerror.h" +#include "prprf.h" +#include "plgetopt.h" + +#include "secutil.h" +#include "secpkcs7.h" +#include "secrng.h" +#if !defined(_WIN32_WCE) +#include <sys/stat.h> +#endif +#include <stdarg.h> + +#ifdef XP_UNIX +#include <unistd.h> +#endif + +/* for SEC_TraverseNames */ +#include "cert.h" +#include "certt.h" +#include "certdb.h" + +typedef struct { + char * name; + CERTCertTrust trust; +} certNameAndTrustEntry; + +typedef struct { + int numCerts; + certNameAndTrustEntry *nameAndTrustEntries; +} certNameAndTrustList; + +SECStatus +sec_CountCerts(CERTCertificate *cert, SECItem *unknown, void *arg) +{ + (*(int*)arg)++; + return SECSuccess; +} + +SECStatus +sec_CollectCertNamesAndTrust(CERTCertificate *cert, SECItem *unknown, void *arg) +{ + certNameAndTrustList *pCertNames = (certNameAndTrustList*)arg; + char *name; + int i; + + i = pCertNames->numCerts; + name = cert->nickname ? cert->nickname : cert->emailAddr; + + if (name) + pCertNames->nameAndTrustEntries[i].name = PORT_Strdup(name); + else + pCertNames->nameAndTrustEntries[i].name = PORT_Strdup("<unknown>"); + + PORT_Memcpy(&pCertNames->nameAndTrustEntries[i].trust, cert->trust, sizeof(*cert->trust)); + + pCertNames->numCerts++; + + return SECSuccess; +} + + +static int +sec_name_and_trust_compare_by_name(const void *p1, const void *p2) +{ + certNameAndTrustEntry *e1 = (certNameAndTrustEntry *)p1; + certNameAndTrustEntry *e2 = (certNameAndTrustEntry *)p2; + return PORT_Strcmp(e1->name, e2->name); +} + +static int +sec_combine_trust_flags(CERTCertTrust *trust) +{ + if (trust == NULL) + return 0; + return trust->sslFlags | trust->emailFlags | trust->objectSigningFlags; +} + +static int +sec_name_and_trust_compare_by_trust(const void *p1, const void *p2) +{ + certNameAndTrustEntry *e1 = (certNameAndTrustEntry *)p1; + certNameAndTrustEntry *e2 = (certNameAndTrustEntry *)p2; + int e1_is_ca, e2_is_ca; + int e1_is_user, e2_is_user; + int rv; + + e1_is_ca = (sec_combine_trust_flags(&e1->trust) & CERTDB_VALID_CA) != 0; + e2_is_ca = (sec_combine_trust_flags(&e2->trust) & CERTDB_VALID_CA) != 0; + e1_is_user = (sec_combine_trust_flags(&e1->trust) & CERTDB_USER) != 0; + e2_is_user = (sec_combine_trust_flags(&e2->trust) & CERTDB_USER) != 0; + + /* first, sort by user status, then CA status, */ + /* then by actual comparison of CA flags, then by name */ + if ((rv = (e2_is_user - e1_is_user)) == 0 && (rv = (e1_is_ca - e2_is_ca)) == 0) + if (e1_is_ca || (rv = memcmp(&e1->trust, &e2->trust, sizeof(CERTCertTrust))) == 0) + return PORT_Strcmp(e1->name, e2->name); + else + return rv; + else + return rv; +} + +SECStatus +SECU_PrintCertificateNames(CERTCertDBHandle *handle, PRFileDesc *out, + PRBool sortByName, PRBool sortByTrust) +{ + certNameAndTrustList certNames = { 0, NULL }; + int numCerts, i; + SECStatus rv; + int (*comparefn)(const void *, const void *); + char trusts[30]; + + numCerts = 0; + + rv = SEC_TraversePermCerts(handle, sec_CountCerts, &numCerts); + if (rv != SECSuccess) + return SECFailure; + + certNames.nameAndTrustEntries = + (certNameAndTrustEntry *)PORT_Alloc(numCerts * sizeof(certNameAndTrustEntry)); + if (certNames.nameAndTrustEntries == NULL) + return SECFailure; + + rv = SEC_TraversePermCerts(handle, sec_CollectCertNamesAndTrust, &certNames); + if (rv != SECSuccess) + return SECFailure; + + if (sortByName) + comparefn = sec_name_and_trust_compare_by_name; + else if (sortByTrust) + comparefn = sec_name_and_trust_compare_by_trust; + else + comparefn = NULL; + + if (comparefn) + qsort(certNames.nameAndTrustEntries, certNames.numCerts, + sizeof(certNameAndTrustEntry), comparefn); + + PR_fprintf(out, "\n%-60s %-5s\n\n", "Certificate Name", "Trust Attributes"); + for (i = 0; i < certNames.numCerts; i++) { + PORT_Memset (trusts, 0, sizeof(trusts)); + printflags(trusts, certNames.nameAndTrustEntries[i].trust.sslFlags); + PORT_Strcat(trusts, ","); + printflags(trusts, certNames.nameAndTrustEntries[i].trust.emailFlags); + PORT_Strcat(trusts, ","); + printflags(trusts, certNames.nameAndTrustEntries[i].trust.objectSigningFlags); + PR_fprintf(out, "%-60s %-5s\n", + certNames.nameAndTrustEntries[i].name, trusts); + } + PR_fprintf(out, "\n"); + PR_fprintf(out, "p Valid peer\n"); + PR_fprintf(out, "P Trusted peer (implies p)\n"); + PR_fprintf(out, "c Valid CA\n"); + PR_fprintf(out, "T Trusted CA to issue client certs (implies c)\n"); + PR_fprintf(out, "C Trusted CA to certs(only server certs for ssl) (implies c)\n"); + PR_fprintf(out, "u User cert\n"); + PR_fprintf(out, "w Send warning\n"); + + for (i = 0; i < certNames.numCerts; i++) + PORT_Free(certNames.nameAndTrustEntries[i].name); + PORT_Free(certNames.nameAndTrustEntries); + + return rv; +} diff --git a/security/nss/cmd/lib/secerror.c b/security/nss/cmd/lib/secerror.c new file mode 100644 index 000000000..857704b79 --- /dev/null +++ b/security/nss/cmd/lib/secerror.c @@ -0,0 +1,107 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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" + +struct tuple_str { + PRErrorCode errNum; + const char * errString; +}; + +typedef struct tuple_str tuple_str; + +#define ER2(a,b) {a, b}, +#define ER3(a,b,c) {a, c}, + +#include "secerr.h" +#include "sslerr.h" + +const tuple_str errStrings[] = { + +/* keep this list in asceding order of error numbers */ +#include "SSLerrs.h" +#include "SECerrs.h" +#include "NSPRerrs.h" + +}; + +const PRInt32 numStrings = sizeof(errStrings) / sizeof(tuple_str); + +/* Returns a UTF-8 encoded constant error string for "errNum". + * Returns NULL of errNum is unknown. + */ +const char * +SECU_Strerror(PRErrorCode errNum) { + PRInt32 low = 0; + PRInt32 high = numStrings - 1; + PRInt32 i; + PRErrorCode num; + static int initDone; + + /* make sure table is in ascending order. + * binary search depends on it. + */ + if (!initDone) { + PRErrorCode lastNum = ((PRInt32)0x80000000); + for (i = low; i <= high; ++i) { + num = errStrings[i].errNum; + if (num <= lastNum) { + fprintf(stderr, +"sequence error in error strings at item %d\n" +"error %d (%s)\n" +"should come after \n" +"error %d (%s)\n", + i, lastNum, errStrings[i-1].errString, + num, errStrings[i].errString); + } + lastNum = num; + } + initDone = 1; + } + + /* Do binary search of table. */ + while (low + 1 < high) { + i = (low + high) / 2; + num = errStrings[i].errNum; + if (errNum == num) + return errStrings[i].errString; + if (errNum < num) + high = i; + else + low = i; + } + if (errNum == errStrings[low].errNum) + return errStrings[low].errString; + if (errNum == errStrings[high].errNum) + return errStrings[high].errString; + return NULL; +} diff --git a/security/nss/cmd/lib/secpwd.c b/security/nss/cmd/lib/secpwd.c new file mode 100644 index 000000000..9a505a720 --- /dev/null +++ b/security/nss/cmd/lib/secpwd.c @@ -0,0 +1,199 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "secutil.h" + +/* + * NOTE: The contents of this file are NOT used by the client. + * (They are part of the security library as a whole, but they are + * NOT USED BY THE CLIENT.) Do not change things on behalf of the + * client (like localizing strings), or add things that are only + * for the client (put them elsewhere). + */ + + +#ifdef XP_UNIX +#include <termios.h> +#include <unistd.h> +#endif + +#if( defined(_WINDOWS) && !defined(_WIN32_WCE)) || defined(XP_OS2_VACPP) +#include <conio.h> +#include <io.h> +#define QUIET_FGETS quiet_fgets +static char * quiet_fgets (char *buf, int length, FILE *input); +#else +#define QUIET_FGETS fgets +#endif + +static void echoOff(int fd) +{ +#if defined(XP_UNIX) && !defined(VMS) + if (isatty(fd)) { + struct termios tio; + tcgetattr(fd, &tio); + tio.c_lflag &= ~ECHO; + tcsetattr(fd, TCSAFLUSH, &tio); + } +#endif +} + +static void echoOn(int fd) +{ +#if defined(XP_UNIX) && !defined(VMS) + if (isatty(fd)) { + struct termios tio; + tcgetattr(fd, &tio); + tio.c_lflag |= ECHO; + tcsetattr(fd, TCSAFLUSH, &tio); + } +#endif +} + +char *SEC_GetPassword(FILE *input, FILE *output, char *prompt, + PRBool (*ok)(char *)) +{ +#if defined(_WINDOWS) + int isTTY = (input == stdin); +#define echoOn(x) +#define echoOff(x) +#else + int infd = fileno(input); + int isTTY = isatty(infd); +#endif + char phrase[200]; + + for (;;) { + /* Prompt for password */ + if (isTTY) { + fprintf(output, "%s", prompt); + fflush (output); + echoOff(infd); + } + + QUIET_FGETS ( phrase, sizeof(phrase), input); + + if (isTTY) { + fprintf(output, "\n"); + echoOn(infd); + } + + /* stomp on newline */ + phrase[PORT_Strlen(phrase)-1] = 0; + + /* Validate password */ + if (!(*ok)(phrase)) { + /* Not weird enough */ + if (!isTTY) return 0; + fprintf(output, "Password must be at least 8 characters long with one or more\n"); + fprintf(output, "non-alphabetic characters\n"); + continue; + } + return (char*) PORT_Strdup(phrase); + } +} + + + +PRBool SEC_CheckPassword(char *cp) +{ + int len; + char *end; + + len = PORT_Strlen(cp); + if (len < 8) { + return PR_FALSE; + } + end = cp + len; + while (cp < end) { + unsigned char ch = *cp++; + if (!((ch >= 'A') && (ch <= 'Z')) && + !((ch >= 'a') && (ch <= 'z'))) { + /* pass phrase has at least one non alphabetic in it */ + return PR_TRUE; + } + } + return PR_FALSE; +} + +PRBool SEC_BlindCheckPassword(char *cp) +{ + if (cp != NULL) { + return PR_TRUE; + } + return PR_FALSE; +} + +/* Get a password from the input terminal, without echoing */ + +#if defined(_WINDOWS) || defined(XP_OS2_VACPP) +static char * quiet_fgets (char *buf, int length, FILE *input) + { + int c; + char *end = buf; + + /* fflush (input); */ + memset (buf, 0, length); + +#ifndef XP_OS2_VACPP + if (input != stdin) { + return fgets(buf,length,input); + } +#else + if (!isatty(fileno(input))) { + return fgets(buf,length,input); + } +#endif + + while (1) + { +#if defined (_WIN32_WCE) + c = getchar(); /* gets a character from stdin */ +#else + c = getch(); /* getch gets a character from the console */ +#endif + if (c == '\b') + { + if (end > buf) + end--; + } + + else if (--length > 0) + *end++ = c; + + if (!c || c == '\n' || c == '\r') + break; + } + + return buf; + } +#endif diff --git a/security/nss/cmd/lib/secutil.c b/security/nss/cmd/lib/secutil.c new file mode 100644 index 000000000..7e4570703 --- /dev/null +++ b/security/nss/cmd/lib/secutil.c @@ -0,0 +1,2622 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ +/* +** secutil.c - various functions used by security stuff +** +*/ + +#include "prtypes.h" +#include "prtime.h" +#include "prlong.h" +#include "prerror.h" +#include "prprf.h" +#include "plgetopt.h" +#include "prenv.h" + +#include "secutil.h" +#include "secpkcs7.h" +#include "secrng.h" +#include <stdarg.h> +#if !defined(_WIN32_WCE) +#include <sys/stat.h> +#include <errno.h> +#endif + +#ifdef XP_UNIX +#include <unistd.h> +#endif + +/* for SEC_TraverseNames */ +#include "cert.h" +#include "certt.h" +#include "certdb.h" + +/* #include "secmod.h" */ +#include "pk11func.h" +#include "secoid.h" + +static char consoleName[] = { +#ifdef XP_UNIX +#ifdef VMS + "TT" +#else + "/dev/tty" +#endif +#else +#ifdef XP_OS2 + "\\DEV\\CON" +#else + "CON:" +#endif +#endif +}; + +char * +SECU_GetString(int16 error_number) +{ + + static char errString[80]; + sprintf(errString, "Unknown error string (%d)", error_number); + return errString; +} + +void +SECU_PrintError(char *progName, char *msg, ...) +{ + va_list args; + PRErrorCode err = PORT_GetError(); + const char * errString = SECU_Strerror(err); + + va_start(args, msg); + + fprintf(stderr, "%s: ", progName); + vfprintf(stderr, msg, args); + if (errString != NULL && PORT_Strlen(errString) > 0) + fprintf(stderr, ": %s\n", errString); + else + fprintf(stderr, ": error %d\n", (int)err); + + va_end(args); +} + +void +SECU_PrintSystemError(char *progName, char *msg, ...) +{ + va_list args; + + va_start(args, msg); + fprintf(stderr, "%s: ", progName); + vfprintf(stderr, msg, args); +#if defined(_WIN32_WCE) + fprintf(stderr, ": %d\n", PR_GetOSError()); +#else + fprintf(stderr, ": %s\n", strerror(errno)); +#endif + va_end(args); +} + +static void +secu_ClearPassword(char *p) +{ + if (p) { + PORT_Memset(p, 0, PORT_Strlen(p)); + PORT_Free(p); + } +} + +char * +SECU_GetPasswordString(void *arg, char *prompt) +{ +#ifndef _WINDOWS + char *p = NULL; + FILE *input, *output; + + /* open terminal */ + input = fopen(consoleName, "r"); + if (input == NULL) { + fprintf(stderr, "Error opening input terminal for read\n"); + return NULL; + } + + output = fopen(consoleName, "w"); + if (output == NULL) { + fprintf(stderr, "Error opening output terminal for write\n"); + return NULL; + } + + p = SEC_GetPassword (input, output, prompt, SEC_BlindCheckPassword); + + + fclose(input); + fclose(output); + + return p; + +#else + /* Win32 version of above. opening the console may fail + on windows95, and certainly isn't necessary.. */ + + char *p = NULL; + + p = SEC_GetPassword (stdin, stdout, prompt, SEC_BlindCheckPassword); + return p; + +#endif +} + + +/* + * p a s s w o r d _ h a r d c o d e + * + * A function to use the password passed in the -f(pwfile) argument + * of the command line. + * After use once, null it out otherwise PKCS11 calls us forever.? + * + */ +char * +SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg) +{ + unsigned char phrase[200]; + PRFileDesc *fd; + PRInt32 nb; + char *pwFile = arg; + int i; + + if (!pwFile) + return 0; + + if (retry) { + return 0; /* no good retrying - the files contents will be the same */ + } + + fd = PR_Open(pwFile, PR_RDONLY, 0); + if (!fd) { + fprintf(stderr, "No password file \"%s\" exists.\n", pwFile); + return NULL; + } + + nb = PR_Read(fd, phrase, sizeof(phrase)); + + PR_Close(fd); + /* handle the Windows EOL case */ + i = 0; + while (phrase[i] != '\r' && phrase[i] != '\n' && i < nb) i++; + phrase[i] = '\0'; + if (nb == 0) { + fprintf(stderr,"password file contains no data\n"); + return NULL; + } + return (char*) PORT_Strdup((char*)phrase); +} + +char * +SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg) +{ + char prompt[255]; + secuPWData *pwdata = (secuPWData *)arg; + secuPWData pwnull = { PW_NONE, 0 }; + char *pw; + + if (pwdata == NULL) + pwdata = &pwnull; + + if (retry && pwdata->source != PW_NONE) { + PR_fprintf(PR_STDERR, "incorrect password entered at command line.\n"); + return NULL; + } + + switch (pwdata->source) { + case PW_NONE: + sprintf(prompt, "Enter Password or Pin for \"%s\":", + PK11_GetTokenName(slot)); + return SECU_GetPasswordString(NULL, prompt); + case PW_FROMFILE: + /* Instead of opening and closing the file every time, get the pw + * once, then keep it in memory (duh). + */ + pw = SECU_FilePasswd(slot, retry, pwdata->data); + pwdata->source = PW_PLAINTEXT; + pwdata->data = PL_strdup(pw); + /* it's already been dup'ed */ + return pw; + case PW_PLAINTEXT: + return PL_strdup(pwdata->data); + default: + break; + } + + PR_fprintf(PR_STDERR, "Password check failed: No password found.\n"); + return NULL; +} + +char * +secu_InitSlotPassword(PK11SlotInfo *slot, PRBool retry, void *arg) +{ + char *p0 = NULL; + char *p1 = NULL; + FILE *input, *output; + secuPWData *pwdata = arg; + + if (pwdata->source == PW_FROMFILE) { + return SECU_FilePasswd(slot, retry, pwdata->data); + } + if (pwdata->source == PW_PLAINTEXT) { + return PL_strdup(pwdata->data); + } + + /* PW_NONE - get it from tty */ + /* open terminal */ +#ifdef _WINDOWS + input = stdin; +#else + input = fopen(consoleName, "r"); +#endif + if (input == NULL) { + PR_fprintf(PR_STDERR, "Error opening input terminal for read\n"); + return NULL; + } + + /* we have no password, so initialize database with one */ + PR_fprintf(PR_STDERR, + "Enter a password which will be used to encrypt your keys.\n" + "The password should be at least 8 characters long,\n" + "and should contain at least one non-alphabetic character.\n\n"); + + output = fopen(consoleName, "w"); + if (output == NULL) { + PR_fprintf(PR_STDERR, "Error opening output terminal for write\n"); + return NULL; + } + + + for (;;) { + if (p0) + PORT_Free(p0); + p0 = SEC_GetPassword(input, output, "Enter new password: ", + SEC_BlindCheckPassword); + + if (p1) + PORT_Free(p1); + p1 = SEC_GetPassword(input, output, "Re-enter password: ", + SEC_BlindCheckPassword); + if (p0 && p1 && !PORT_Strcmp(p0, p1)) { + break; + } + PR_fprintf(PR_STDERR, "Passwords do not match. Try again.\n"); + } + + /* clear out the duplicate password string */ + secu_ClearPassword(p1); + + fclose(input); + fclose(output); + + return p0; +} + +SECStatus +SECU_ChangePW(PK11SlotInfo *slot, char *passwd, char *pwFile) +{ + SECStatus rv; + secuPWData pwdata, newpwdata; + char *oldpw = NULL, *newpw = NULL; + + if (passwd) { + pwdata.source = PW_PLAINTEXT; + pwdata.data = passwd; + } else if (pwFile) { + pwdata.source = PW_FROMFILE; + pwdata.data = pwFile; + } else { + pwdata.source = PW_NONE; + pwdata.data = NULL; + } + + if (PK11_NeedUserInit(slot)) { + newpw = secu_InitSlotPassword(slot, PR_FALSE, &pwdata); + rv = PK11_InitPin(slot, (char*)NULL, newpw); + goto done; + } + + for (;;) { + oldpw = SECU_GetModulePassword(slot, PR_FALSE, &pwdata); + + if (PK11_CheckUserPassword(slot, oldpw) != SECSuccess) { + if (pwdata.source == PW_NONE) { + PR_fprintf(PR_STDERR, "Invalid password. Try again.\n"); + } else { + PR_fprintf(PR_STDERR, "Invalid password.\n"); + PORT_Memset(oldpw, 0, PL_strlen(oldpw)); + PORT_Free(oldpw); + return SECFailure; + } + } else + break; + + PORT_Free(oldpw); + } + + newpwdata.source = PW_NONE; + newpwdata.data = NULL; + + newpw = secu_InitSlotPassword(slot, PR_FALSE, &newpwdata); + + if (PK11_ChangePW(slot, oldpw, newpw) != SECSuccess) { + PR_fprintf(PR_STDERR, "Failed to change password.\n"); + return SECFailure; + } + + PORT_Memset(oldpw, 0, PL_strlen(oldpw)); + PORT_Free(oldpw); + + PR_fprintf(PR_STDOUT, "Password changed successfully.\n"); + +done: + PORT_Memset(newpw, 0, PL_strlen(newpw)); + PORT_Free(newpw); + return SECSuccess; +} + +struct matchobj { + SECItem index; + char *nname; + PRBool found; +}; + +char * +SECU_DefaultSSLDir(void) +{ + char *dir; + static char sslDir[1000]; + + dir = PR_GetEnv("SSL_DIR"); + if (!dir) + return NULL; + + sprintf(sslDir, "%s", dir); + + if (sslDir[strlen(sslDir)-1] == '/') + sslDir[strlen(sslDir)-1] = 0; + + return sslDir; +} + +char * +SECU_AppendFilenameToDir(char *dir, char *filename) +{ + static char path[1000]; + + if (dir[strlen(dir)-1] == '/') + sprintf(path, "%s%s", dir, filename); + else + sprintf(path, "%s/%s", dir, filename); + return path; +} + +char * +SECU_ConfigDirectory(const char* base) +{ + static PRBool initted = PR_FALSE; + const char *dir = ".netscape"; + char *home; + static char buf[1000]; + + if (initted) return buf; + + + if (base == NULL || *base == 0) { + home = PR_GetEnv("HOME"); + if (!home) home = ""; + + if (*home && home[strlen(home) - 1] == '/') + sprintf (buf, "%.900s%s", home, dir); + else + sprintf (buf, "%.900s/%s", home, dir); + } else { + sprintf(buf, "%.900s", base); + if (buf[strlen(buf) - 1] == '/') + buf[strlen(buf) - 1] = 0; + } + + + initted = PR_TRUE; + return buf; +} + +/*Turn off SSL for now */ +/* This gets called by SSL when server wants our cert & key */ +int +SECU_GetClientAuthData(void *arg, PRFileDesc *fd, + struct CERTDistNamesStr *caNames, + struct CERTCertificateStr **pRetCert, + struct SECKEYPrivateKeyStr **pRetKey) +{ + SECKEYPrivateKey *key; + CERTCertificate *cert; + int errsave; + + if (arg == NULL) { + fprintf(stderr, "no key/cert name specified for client auth\n"); + return -1; + } + cert = PK11_FindCertFromNickname(arg, NULL); + errsave = PORT_GetError(); + if (!cert) { + if (errsave == SEC_ERROR_BAD_PASSWORD) + fprintf(stderr, "Bad password\n"); + else if (errsave > 0) + fprintf(stderr, "Unable to read cert (error %d)\n", errsave); + else if (errsave == SEC_ERROR_BAD_DATABASE) + fprintf(stderr, "Unable to get cert from database (%d)\n", errsave); + else + fprintf(stderr, "SECKEY_FindKeyByName: internal error %d\n", errsave); + return -1; + } + + key = PK11_FindKeyByAnyCert(arg,NULL); + if (!key) { + fprintf(stderr, "Unable to get key (%d)\n", PORT_GetError()); + return -1; + } + + + *pRetCert = cert; + *pRetKey = key; + + return 0; +} + +SECStatus +secu_StdinToItem(SECItem *dst) +{ + unsigned char buf[1000]; + PRInt32 numBytes; + PRBool notDone = PR_TRUE; + + dst->len = 0; + dst->data = NULL; + + while (notDone) { + numBytes = PR_Read(PR_STDIN, buf, sizeof(buf)); + + if (numBytes < 0) { + PORT_SetError(PR_IO_ERROR); + return SECFailure; + } + + if (numBytes == 0) + break; + + if (buf[numBytes-1] == '\n') { + buf[numBytes-1] = '\0'; + notDone = PR_FALSE; + } + + if (dst->data) { + dst->data = (unsigned char*)PORT_Realloc(dst->data, + dst->len+numBytes); + PORT_Memcpy(dst->data+dst->len, buf, numBytes); + } else { + dst->data = (unsigned char*)PORT_Alloc(numBytes); + PORT_Memcpy(dst->data, buf, numBytes); + } + dst->len += numBytes; + } + + return SECSuccess; +} + +SECStatus +SECU_FileToItem(SECItem *dst, PRFileDesc *src) +{ + PRFileInfo info; + PRInt32 numBytes; + PRStatus prStatus; + + if (src == PR_STDIN) + return secu_StdinToItem(dst); + + prStatus = PR_GetOpenFileInfo(src, &info); + + if (prStatus != PR_SUCCESS) { + PORT_SetError(SEC_ERROR_IO); + return SECFailure; + } + + /* XXX workaround for 3.1, not all utils zero dst before sending */ + dst->data = 0; + if (!SECITEM_AllocItem(NULL, dst, info.size)) + goto loser; + + numBytes = PR_Read(src, dst->data, info.size); + if (numBytes != info.size) { + PORT_SetError(SEC_ERROR_IO); + goto loser; + } + + return SECSuccess; +loser: + SECITEM_FreeItem(dst, PR_FALSE); + return SECFailure; +} + +SECStatus +SECU_TextFileToItem(SECItem *dst, PRFileDesc *src) +{ + PRFileInfo info; + PRInt32 numBytes; + PRStatus prStatus; + unsigned char *buf; + + if (src == PR_STDIN) + return secu_StdinToItem(dst); + + prStatus = PR_GetOpenFileInfo(src, &info); + + if (prStatus != PR_SUCCESS) { + PORT_SetError(SEC_ERROR_IO); + return SECFailure; + } + + buf = (unsigned char*)PORT_Alloc(info.size); + if (!buf) + return SECFailure; + + numBytes = PR_Read(src, buf, info.size); + if (numBytes != info.size) { + PORT_SetError(SEC_ERROR_IO); + goto loser; + } + + if (buf[numBytes-1] == '\n') numBytes--; +#ifdef _WINDOWS + if (buf[numBytes-1] == '\r') numBytes--; +#endif + + /* XXX workaround for 3.1, not all utils zero dst before sending */ + dst->data = 0; + if (!SECITEM_AllocItem(NULL, dst, numBytes)) + goto loser; + + memcpy(dst->data, buf, numBytes); + + PORT_Free(buf); + return SECSuccess; +loser: + PORT_Free(buf); + return SECFailure; +} + +SECStatus +SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii) +{ + SECStatus rv; + char *asc, *body, *trailer; + if (ascii) { + /* First convert ascii to binary */ + SECItem filedata; + + /* Read in ascii data */ + rv = SECU_FileToItem(&filedata, inFile); + asc = (char *)filedata.data; + if (!asc) { + fprintf(stderr, "unable to read data from input file\n"); + return SECFailure; + } + + /* check for headers and trailers and remove them */ + if ((body = strstr(asc, "-----BEGIN")) != NULL) { + body = PORT_Strchr(body, '\n') + 1; + trailer = strstr(body, "-----END"); + if (trailer != NULL) { + *trailer = '\0'; + } else { + fprintf(stderr, "input has header but no trailer\n"); + return SECFailure; + } + } else { + body = asc; + } + + /* Convert to binary */ + rv = ATOB_ConvertAsciiToItem(der, body); + if (rv) { + fprintf(stderr, "error converting ascii to binary (%s)\n", + SECU_Strerror(PORT_GetError())); + return SECFailure; + } + PORT_Free(asc); + } else { + /* Read in binary der */ + rv = SECU_FileToItem(der, inFile); + if (rv) { + fprintf(stderr, "error converting der (%s)\n", + SECU_Strerror(PORT_GetError())); + return SECFailure; + } + } + return SECSuccess; +} + +#define INDENT_MULT 4 +void +SECU_Indent(FILE *out, int level) +{ + int i; + for (i = 0; i < level; i++) { + fprintf(out, " "); + } +} + +static void secu_Newline(FILE *out) +{ + fprintf(out, "\n"); +} + +void +SECU_PrintAsHex(FILE *out, SECItem *data, const char *m, int level) +{ + unsigned i; + int column; + PRBool isString = PR_TRUE; + + if ( m ) { + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + level++; + } + + SECU_Indent(out, level); column = level*INDENT_MULT; + for (i = 0; i < data->len; i++) { + unsigned char val = data->data[i]; + + if (isString && val && !isprint(val)) { + isString = PR_FALSE; + } + if (i != data->len - 1) { + fprintf(out, "%02x:", data->data[i]); + column += 3; + } else { + fprintf(out, "%02x", data->data[i]); + column += 2; + break; + } + if (column > 76 || (i % 16 == 15)) { + secu_Newline(out); + SECU_Indent(out, level); column = level*INDENT_MULT; + } + } + if (isString) { + secu_Newline(out); + SECU_Indent(out, level); column = level*INDENT_MULT; + for (i = 0; i < data->len; i++) { + unsigned char val = data->data[i]; + + if (val) { + fprintf(out,"%c",val); + column++; + } else { + column = 77; + } + if (column > 76) { + secu_Newline(out); + SECU_Indent(out, level); column = level*INDENT_MULT; + } + } + } + + level--; + if (column != level*INDENT_MULT) { + secu_Newline(out); + } +} + +static const char *hex = "0123456789abcdef"; + +static const char printable[257] = { + "................" /* 0x */ + "................" /* 1x */ + " !\"#$%&'()*+,-./" /* 2x */ + "0123456789:;<=>?" /* 3x */ + "@ABCDEFGHIJKLMNO" /* 4x */ + "PQRSTUVWXYZ[\\]^_" /* 5x */ + "`abcdefghijklmno" /* 6x */ + "pqrstuvwxyz{|}~." /* 7x */ + "................" /* 8x */ + "................" /* 9x */ + "................" /* ax */ + "................" /* bx */ + "................" /* cx */ + "................" /* dx */ + "................" /* ex */ + "................" /* fx */ +}; + +void +SECU_PrintBuf(FILE *out, const char *msg, const void *vp, int len) +{ + const unsigned char *cp = (const unsigned char *)vp; + char buf[80]; + char *bp; + char *ap; + + fprintf(out, "%s [Len: %d]\n", msg, len); + memset(buf, ' ', sizeof buf); + bp = buf; + ap = buf + 50; + while (--len >= 0) { + unsigned char ch = *cp++; + *bp++ = hex[(ch >> 4) & 0xf]; + *bp++ = hex[ch & 0xf]; + *bp++ = ' '; + *ap++ = printable[ch]; + if (ap - buf >= 66) { + *ap = 0; + fprintf(out, " %s\n", buf); + memset(buf, ' ', sizeof buf); + bp = buf; + ap = buf + 50; + } + } + if (bp > buf) { + *ap = 0; + fprintf(out, " %s\n", buf); + } +} + +void +SECU_PrintInteger(FILE *out, SECItem *i, char *m, int level) +{ + int iv; + + if (!i || !i->len || !i->data) { + SECU_Indent(out, level); + if (m) { + fprintf(out, "%s: (null)\n", m); + } else { + fprintf(out, "(null)\n"); + } + } else if (i->len > 4) { + SECU_PrintAsHex(out, i, m, level); + } else { + iv = DER_GetInteger(i); + SECU_Indent(out, level); + if (m) { + fprintf(out, "%s: %d (0x%x)\n", m, iv, iv); + } else { + fprintf(out, "%d (0x%x)\n", iv, iv); + } + } +} + +void +SECU_PrintString(FILE *out, SECItem *i, char *m, int level) +{ + char *string; + unsigned char *data = i->data; + int len = i->len; + int lenlen; + int tag; + + string = PORT_ZAlloc(i->len+1); + + tag = *data++; len--; + if (data[1] & 0x80) { + lenlen = data[1] & 0x1f; + } else { + lenlen = 1; + } + data += lenlen; len -= lenlen; + if (len <= 0) return; + PORT_Memcpy(string,data,len); + + /* should check the validity of tag, and convert the string as necessary */ + SECU_Indent(out, level); + if (m) { + fprintf(out, "%s: \"%s\"\n", m, string); + } else { + fprintf(out, "\"%s\"\n", string); + } +} + +static void +secu_PrintBoolean(FILE *out, SECItem *i, char *m, int level) +{ + int val = 0; + + if ( i->data ) { + val = i->data[0]; + } + + if (m) { + SECU_Indent(out, level); fprintf(out, "%s:\n", m); level++; + } + if ( val ) { + SECU_Indent(out, level); fprintf(out, "%s\n", "True"); + } else { + SECU_Indent(out, level); fprintf(out, "%s\n", "False"); + } +} + +/* + * Format and print "time". If the tag message "m" is not NULL, + * do indent formatting based on "level" and add a newline afterward; + * otherwise just print the formatted time string only. + */ +static void +secu_PrintTime(FILE *out, int64 time, char *m, int level) +{ + PRExplodedTime printableTime; + char *timeString; + + /* Convert to local time */ + PR_ExplodeTime(time, PR_GMTParameters, &printableTime); + + timeString = PORT_Alloc(100); + if (timeString == NULL) + return; + + if (m != NULL) { + SECU_Indent(out, level); + fprintf(out, "%s: ", m); + } + + PR_FormatTime(timeString, 100, "%a %b %d %H:%M:%S %Y", &printableTime); + fprintf(out, timeString); + + if (m != NULL) + fprintf(out, "\n"); + + PORT_Free(timeString); +} + +/* + * Format and print the UTC Time "t". If the tag message "m" is not NULL, + * do indent formatting based on "level" and add a newline afterward; + * otherwise just print the formatted time string only. + */ +void +SECU_PrintUTCTime(FILE *out, SECItem *t, char *m, int level) +{ + int64 time; + SECStatus rv; + + rv = DER_UTCTimeToTime(&time, t); + if (rv != SECSuccess) + return; + + secu_PrintTime(out, time, m, level); +} + +/* + * Format and print the Generalized Time "t". If the tag message "m" + * is not NULL, * do indent formatting based on "level" and add a newline + * afterward; otherwise just print the formatted time string only. + */ +void +SECU_PrintGeneralizedTime(FILE *out, SECItem *t, char *m, int level) +{ + int64 time; + SECStatus rv; + + + rv = DER_GeneralizedTimeToTime(&time, t); + if (rv != SECSuccess) + return; + + secu_PrintTime(out, time, m, level); +} + +static void secu_PrintAny(FILE *out, SECItem *i, char *m, int level); + +void +SECU_PrintSet(FILE *out, SECItem *t, char *m, int level) +{ + int type= t->data[0] & SEC_ASN1_TAGNUM_MASK; + int start; + unsigned char *bp; + + SECU_Indent(out, level); + if (m) { + fprintf(out, "%s: ", m); + } + + fprintf(out,"%s {\n", type == SEC_ASN1_SET ? "Set" : "Sequence"); /* } */ + + start = 2; + if (t->data[1] & 0x80) { + start += (t->data[1] & 0x7f); + } + for (bp=&t->data[start]; bp < &t->data[t->len]; ) { + SECItem tmp; + unsigned int i,len,lenlen; + + if (bp[1] & 0x80) { + lenlen = bp[1] & 0x1f; + len = 0; + for (i=0; i < lenlen; i++) { + len = len * 255 + bp[2+i]; + } + } else { + lenlen = 1; + len = bp[1]; + } + tmp.len = len+lenlen+1; + if (tmp.len > &t->data[t->len] - bp) { + tmp.len = &t->data[t->len] - bp; + } + tmp.data = bp; + bp += tmp.len; + secu_PrintAny(out,&tmp,NULL,level+1); + } + /* { */SECU_Indent(out, level); fprintf(out, "}\n"); +} + +static void +secu_PrintContextSpecific(FILE *out, SECItem *i, char *m, int level) +{ + int type= i->data[0] & SEC_ASN1_TAGNUM_MASK; + SECItem tmp; + int start; + + SECU_Indent(out, level); + if (m) { + fprintf(out, "%s: ", m); + } + + fprintf(out,"[%d]\n", type); + start = 2; + if (i->data[1] & 0x80) { + start = (i->data[1] & 0x7f) +1; + } + tmp.data = &i->data[start]; + tmp.len = i->len -start; + SECU_PrintAsHex(out, &tmp, m, level+1); +} + +static void +secu_PrintOctetString(FILE *out, SECItem *i, char *m, int level) +{ + SECItem tmp; + int start; + + start = 2; + if (i->data[1] & 0x80) { + start = (i->data[1] & 0x7f) +1; + } + tmp.data = &i->data[start]; + tmp.len = i->len - start; + SECU_PrintAsHex(out, &tmp, m, level); +} + +static void +secu_PrintBitString(FILE *out, SECItem *i, char *m, int level) +{ + SECItem tmp; + int start; + int unused_bits; + + start = 2; + if (i->data[1] & 0x80) { + start = (i->data[1] & 0x7f) + 1; + } + unused_bits = i->data[start++]; + tmp.data = &i->data[start]; + tmp.len = i->len - start; + SECU_PrintAsHex(out, &tmp, m, level); + if (unused_bits) { + SECU_Indent(out, level + 1); + fprintf(out, "(%d least significant bits unused)\n", unused_bits); + } +} + +static void +secu_PrintUniversal(FILE *out, SECItem *i, char *m, int level) +{ + switch (i->data[0] & SEC_ASN1_TAGNUM_MASK) { + case SEC_ASN1_INTEGER: + SECU_PrintInteger(out, i, m, level); + break; + case SEC_ASN1_OBJECT_ID: + SECU_PrintObjectID(out, i, m, level); + break; + case SEC_ASN1_BOOLEAN: + secu_PrintBoolean(out, i, m, level); + break; + case SEC_ASN1_UTF8_STRING: + case SEC_ASN1_PRINTABLE_STRING: + case SEC_ASN1_VISIBLE_STRING: + case SEC_ASN1_BMP_STRING: + case SEC_ASN1_IA5_STRING: + case SEC_ASN1_T61_STRING: + case SEC_ASN1_UNIVERSAL_STRING: + SECU_PrintString(out, i, m, level); + break; + case SEC_ASN1_GENERALIZED_TIME: + SECU_PrintGeneralizedTime(out, i, m, level); + break; + case SEC_ASN1_UTC_TIME: + SECU_PrintUTCTime(out, i, m, level); + break; + case SEC_ASN1_NULL: + SECU_Indent(out, level); fprintf(out, "%s: NULL\n", m); + break; + case SEC_ASN1_SET: + case SEC_ASN1_SEQUENCE: + SECU_PrintSet(out, i, m, level); + break; + case SEC_ASN1_OCTET_STRING: + secu_PrintOctetString(out, i, m, level); + break; + case SEC_ASN1_BIT_STRING: + secu_PrintBitString(out, i, m, level); + break; + default: + SECU_PrintAsHex(out, i, m, level); + break; + } +} + +static void +secu_PrintAny(FILE *out, SECItem *i, char *m, int level) +{ + if ( i && i->len && i->data ) { + switch (i->data[0] & SEC_ASN1_CLASS_MASK) { + case SEC_ASN1_CONTEXT_SPECIFIC: + secu_PrintContextSpecific(out, i, m, level); + break; + case SEC_ASN1_UNIVERSAL: + secu_PrintUniversal(out, i, m, level); + break; + default: + SECU_PrintAsHex(out, i, m, level); + break; + } + } +} + +static int +secu_PrintValidity(FILE *out, CERTValidity *v, char *m, int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintUTCTime(out, &v->notBefore, "Not Before", level+1); + SECU_PrintUTCTime(out, &v->notAfter, "Not After", level+1); + return 0; +} + +void +SECU_PrintObjectID(FILE *out, SECItem *oid, char *m, int level) +{ + const char *name; + SECOidData *oiddata; + + oiddata = SECOID_FindOID(oid); + if (oiddata == NULL) { + SECU_PrintAsHex(out, oid, m, level); + return; + } + name = oiddata->desc; + + SECU_Indent(out, level); + if (m != NULL) + fprintf(out, "%s: ", m); + fprintf(out, "%s\n", name); +} + +void +SECU_PrintAlgorithmID(FILE *out, SECAlgorithmID *a, char *m, int level) +{ + SECU_PrintObjectID(out, &a->algorithm, m, level); + + if (a->parameters.len == 0 + || (a->parameters.len == 2 + && PORT_Memcmp(a->parameters.data, "\005\000", 2) == 0)) { + /* No arguments or NULL argument */ + } else { + /* Print args to algorithm */ + SECU_PrintAsHex(out, &a->parameters, "Args", level+1); + } +} + +static void +secu_PrintAttribute(FILE *out, SEC_PKCS7Attribute *attr, char *m, int level) +{ + SECItem *value; + int i; + char om[100]; + + if (m) { + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + } + + /* + * Should make this smarter; look at the type field and then decode + * and print the value(s) appropriately! + */ + SECU_PrintObjectID(out, &(attr->type), "Type", level+1); + if (attr->values != NULL) { + i = 0; + while ((value = attr->values[i++]) != NULL) { + sprintf(om, "Value (%d)%s", i, attr->encoded ? " (encoded)" : ""); + if (attr->encoded || attr->typeTag == NULL) { + SECU_PrintAsHex(out, value, om, level+1); + } else { + switch (attr->typeTag->offset) { + default: + SECU_PrintAsHex(out, value, om, level+1); + break; + case SEC_OID_PKCS9_CONTENT_TYPE: + SECU_PrintObjectID(out, value, om, level+1); + break; + case SEC_OID_PKCS9_SIGNING_TIME: + SECU_PrintUTCTime(out, value, om, level+1); + break; + } + } + } + } +} + +static void +secu_PrintRSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) +{ +#if 0 /* + * um, yeah, that might be nice, but if you look at the callers + * you will see that they do not *set* this, so this will not work! + * Instead, somebody needs to fix the callers to be smarter about + * public key stuff, if that is important. + */ + PORT_Assert(pk->keyType == rsaKey); +#endif + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &pk->u.rsa.modulus, "Modulus", level+1); + SECU_PrintInteger(out, &pk->u.rsa.publicExponent, "Exponent", level+1); +} + +static void +secu_PrintDSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m, int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &pk->u.dsa.params.prime, "Prime", level+1); + SECU_PrintInteger(out, &pk->u.dsa.params.subPrime, "Subprime", level+1); + SECU_PrintInteger(out, &pk->u.dsa.params.base, "Base", level+1); + SECU_PrintInteger(out, &pk->u.dsa.publicValue, "PublicValue", level+1); +} + +static int +secu_PrintSubjectPublicKeyInfo(FILE *out, PRArenaPool *arena, + CERTSubjectPublicKeyInfo *i, char *msg, int level) +{ + SECKEYPublicKey *pk; + + SECU_Indent(out, level); fprintf(out, "%s:\n", msg); + SECU_PrintAlgorithmID(out, &i->algorithm, "Public Key Algorithm", level+1); + + pk = SECKEY_ExtractPublicKey(i); + if (pk) { + switch (pk->keyType) { + case rsaKey: + secu_PrintRSAPublicKey(out, pk, "RSA Public Key", level +1); + break; + + case dsaKey: + secu_PrintDSAPublicKey(out, pk, "DSA Public Key", level +1); + break; + + case dhKey: + case fortezzaKey: + case keaKey: + case ecKey: + fprintf(out, "unable to format this SPKI algorithm type\n"); + break; + default: + fprintf(out, "unknown SPKI algorithm type\n"); + break; + } + PORT_FreeArena(pk->arena, PR_FALSE); + } else { + SECU_PrintError("Error", "Parsing public key"); + } + + return 0; +} + +static SECStatus +secu_PrintX509InvalidDate(FILE *out, SECItem *value, char *msg, int level) +{ + SECItem decodedValue; + SECStatus rv; + int64 invalidTime; + char *formattedTime = NULL; + + decodedValue.data = NULL; + rv = SEC_ASN1DecodeItem (NULL, &decodedValue, + SEC_ASN1_GET(SEC_GeneralizedTimeTemplate), + value); + if (rv == SECSuccess) { + rv = DER_GeneralizedTimeToTime(&invalidTime, &decodedValue); + if (rv == SECSuccess) { + formattedTime = CERT_GenTime2FormattedAscii + (invalidTime, "%a %b %d %H:%M:%S %Y"); + SECU_Indent(out, level +1); + fprintf (out, "%s: %s\n", msg, formattedTime); + PORT_Free (formattedTime); + } + } + PORT_Free (decodedValue.data); + return (rv); +} + +static SECStatus +PrintExtKeyUsageExten (FILE *out, SECItem *value, char *msg, int level) +{ + CERTOidSequence *os; + SECItem **op; + + SECU_Indent(out, level); fprintf(out, "Extended Key Usage Extension:\n"); + + os = CERT_DecodeOidSequence(value); + if( (CERTOidSequence *)NULL == os ) { + return SECFailure; + } + + for( op = os->oids; *op; op++ ) { + SECOidData *od = SECOID_FindOID(*op); + + if( (SECOidData *)NULL == od ) { + SECU_Indent(out, level+1); + SECU_PrintAsHex(out, *op, "Unknown:", level+2); + secu_Newline(out); + continue; + } + + SECU_Indent(out, level+1); + if( od->desc ) fprintf(out, "%s", od->desc); + else SECU_PrintAsHex(out, &od->oid, "", level+2); + + secu_Newline(out); + } + + return SECSuccess; +} + +char * +itemToString(SECItem *item) +{ + char *string; + + string = PORT_ZAlloc(item->len+1); + if (string == NULL) return NULL; + PORT_Memcpy(string,item->data,item->len); + string[item->len] = 0; + return string; +} + +static SECStatus +secu_PrintPolicyQualifier(FILE *out,CERTPolicyQualifier *policyQualifier,char *msg,int level) +{ + CERTUserNotice *userNotice; + SECItem **itemList = NULL; + char *string; + + SECU_PrintObjectID(out, &policyQualifier->qualifierID , + "Policy Qualifier Name", level); + + switch (policyQualifier->oid) { + case SEC_OID_PKIX_USER_NOTICE_QUALIFIER: + userNotice = CERT_DecodeUserNotice(&policyQualifier->qualifierValue); + if (userNotice) { + if (userNotice->noticeReference.organization.len != 0) { + string=itemToString(&userNotice->noticeReference.organization); + itemList = userNotice->noticeReference.noticeNumbers; + while (*itemList) { + SECU_PrintInteger(out,*itemList,string,level+1); + itemList++; + } + PORT_Free(string); + } + if (userNotice->displayText.len != 0) { + SECU_PrintString(out,&userNotice->displayText, + "Display Text", level+1); + } + break; + } + /* fall through on error */ + case SEC_OID_PKIX_CPS_POINTER_QUALIFIER: + default: + secu_PrintAny(out, &policyQualifier->qualifierValue, "Policy Qualifier Data", level+1); + break; + } + + return SECSuccess; + +} + +static SECStatus +secu_PrintPolicyInfo(FILE *out,CERTPolicyInfo *policyInfo,char *msg,int level) +{ + CERTPolicyQualifier **policyQualifiers; + + policyQualifiers = policyInfo->policyQualifiers; + SECU_PrintObjectID(out, &policyInfo->policyID , "Policy Name", level); + + while (*policyQualifiers != NULL) { + secu_PrintPolicyQualifier(out,*policyQualifiers,"",level+1); + policyQualifiers++; + } + return SECSuccess; + +} + +static SECStatus +secu_PrintPolicy(FILE *out, SECItem *value, char *msg, int level) +{ + CERTCertificatePolicies *policies = NULL; + CERTPolicyInfo **policyInfos; + + if (msg) { + SECU_Indent(out, level); + fprintf(out,"%s: \n",msg); + level++; + } + policies = CERT_DecodeCertificatePoliciesExtension(value); + if (policies == NULL) { + SECU_PrintAsHex(out, value, "Invalid Policy Data", level); + return SECFailure; + } + + policyInfos = policies->policyInfos; + while (*policyInfos != NULL) { + secu_PrintPolicyInfo(out,*policyInfos,"",level); + policyInfos++; + } + + CERT_DestroyCertificatePoliciesExtension(policies); + return SECSuccess; +} + +char *nsTypeBits[] = { +"SSL Client","SSL Server","S/MIME","Object Signing","Reserved","SSL CA","S/MIME CA","ObjectSigning CA" }; + +static SECStatus +secu_PrintBasicConstraints(FILE *out, SECItem *value, char *msg, int level) { + CERTBasicConstraints constraints; + SECStatus rv; + + SECU_Indent(out, level); + if (msg) { + fprintf(out,"%s: ",msg); + } + rv = CERT_DecodeBasicConstraintValue(&constraints,value); + if (rv == SECSuccess && constraints.isCA) { + fprintf(out,"Is a CA with a maximum path length of %d.\n", + constraints.pathLenConstraint); + } else { + fprintf(out,"Is not a CA.\n"); + } + return SECSuccess; +} + +static SECStatus +secu_PrintNSCertType(FILE *out, SECItem *value, char *msg, int level) { + char NS_Type=0; + int len, i, found=0; + + if (value->data[1] & 0x80) { + len = 3; + } else { + len = value->data[1]; + } + if ((value->data[0] != SEC_ASN1_BIT_STRING) || (len < 2)) { + secu_PrintAny(out, value, "Data", level); + return SECSuccess; + } + NS_Type=value->data[3]; + + + if (msg) { + SECU_Indent(out, level); + fprintf(out,"%s: ",msg); + } else { + SECU_Indent(out, level); + fprintf(out,"Netscape Certificate Type: "); + } + for (i=0; i < 8; i++) { + if ( (0x80 >> i) & NS_Type) { + fprintf(out,"%c%s",found?',':'<',nsTypeBits[i]); + found = 1; + } + } + if (found) { fprintf(out,">\n"); } else { fprintf(out,"none\n"); } + return SECSuccess; +} + +void +SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions, + char *msg, int level) +{ + SECOidTag oidTag; + + if ( extensions ) { + SECU_Indent(out, level); fprintf(out, "%s:\n", msg); + + while ( *extensions ) { + SECItem *tmpitem; + SECU_Indent(out, level+1); fprintf(out, "Name:\n"); + + tmpitem = &(*extensions)->id; + SECU_PrintObjectID(out, tmpitem, NULL, level+2); + + tmpitem = &(*extensions)->critical; + if ( tmpitem->len ) { + secu_PrintBoolean(out, tmpitem, "Critical", level+1); + } + + oidTag = SECOID_FindOIDTag (&((*extensions)->id)); + tmpitem = &((*extensions)->value); + + switch (oidTag) { + case SEC_OID_X509_INVALID_DATE: + case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_TIME: + secu_PrintX509InvalidDate(out, tmpitem, "Date", level + 1); + break; + case SEC_OID_X509_CERTIFICATE_POLICIES: + secu_PrintPolicy(out, tmpitem, "Data", level +1); + break; + case SEC_OID_NS_CERT_EXT_BASE_URL: + case SEC_OID_NS_CERT_EXT_REVOCATION_URL: + case SEC_OID_NS_CERT_EXT_CA_REVOCATION_URL: + case SEC_OID_NS_CERT_EXT_CA_CRL_URL: + case SEC_OID_NS_CERT_EXT_CA_CERT_URL: + case SEC_OID_NS_CERT_EXT_CERT_RENEWAL_URL: + case SEC_OID_NS_CERT_EXT_CA_POLICY_URL: + case SEC_OID_NS_CERT_EXT_HOMEPAGE_URL: + case SEC_OID_NS_CERT_EXT_LOST_PASSWORD_URL: + case SEC_OID_OCSP_RESPONDER: + SECU_PrintString(out,tmpitem, "URL", level+1); + break; + case SEC_OID_NS_CERT_EXT_COMMENT: + SECU_PrintString(out,tmpitem, "Comment", level+1); + break; + case SEC_OID_NS_CERT_EXT_SSL_SERVER_NAME: + SECU_PrintString(out,tmpitem, "ServerName", level+1); + break; + case SEC_OID_NS_CERT_EXT_CERT_TYPE: + secu_PrintNSCertType(out,tmpitem,"Data",level+1); + break; + case SEC_OID_X509_BASIC_CONSTRAINTS: + secu_PrintBasicConstraints(out,tmpitem,"Data",level+1); + break; + + case SEC_OID_X509_SUBJECT_ALT_NAME: + case SEC_OID_X509_ISSUER_ALT_NAME: + /* + * We should add at least some of the more interesting cases + * here, but need to have subroutines to back them up. + */ + case SEC_OID_NS_CERT_EXT_NETSCAPE_OK: + case SEC_OID_NS_CERT_EXT_ISSUER_LOGO: + case SEC_OID_NS_CERT_EXT_SUBJECT_LOGO: + case SEC_OID_NS_CERT_EXT_ENTITY_LOGO: + case SEC_OID_NS_CERT_EXT_USER_PICTURE: + case SEC_OID_NS_KEY_USAGE_GOVT_APPROVED: + + /* x.509 v3 Extensions */ + case SEC_OID_X509_SUBJECT_DIRECTORY_ATTR: + case SEC_OID_X509_SUBJECT_KEY_ID: + case SEC_OID_X509_KEY_USAGE: + case SEC_OID_X509_PRIVATE_KEY_USAGE_PERIOD: + case SEC_OID_X509_NAME_CONSTRAINTS: + case SEC_OID_X509_CRL_DIST_POINTS: + case SEC_OID_X509_POLICY_MAPPINGS: + case SEC_OID_X509_POLICY_CONSTRAINTS: + case SEC_OID_X509_AUTH_KEY_ID: + goto defualt; + + case SEC_OID_X509_EXT_KEY_USAGE: + PrintExtKeyUsageExten(out, tmpitem, "", level+1); + break; + + case SEC_OID_X509_AUTH_INFO_ACCESS: + case SEC_OID_X509_CRL_NUMBER: + case SEC_OID_X509_REASON_CODE: + + /* PKIX OIDs */ + case SEC_OID_PKIX_OCSP: + case SEC_OID_PKIX_OCSP_BASIC_RESPONSE: + case SEC_OID_PKIX_OCSP_NONCE: + case SEC_OID_PKIX_OCSP_CRL: + case SEC_OID_PKIX_OCSP_RESPONSE: + case SEC_OID_PKIX_OCSP_NO_CHECK: + case SEC_OID_PKIX_OCSP_ARCHIVE_CUTOFF: + case SEC_OID_PKIX_OCSP_SERVICE_LOCATOR: + case SEC_OID_PKIX_REGCTRL_REGTOKEN: + case SEC_OID_PKIX_REGCTRL_AUTHENTICATOR: + case SEC_OID_PKIX_REGCTRL_PKIPUBINFO: + case SEC_OID_PKIX_REGCTRL_PKI_ARCH_OPTIONS: + case SEC_OID_PKIX_REGCTRL_OLD_CERT_ID: + case SEC_OID_PKIX_REGCTRL_PROTOCOL_ENC_KEY: + case SEC_OID_PKIX_REGINFO_UTF8_PAIRS: + case SEC_OID_PKIX_REGINFO_CERT_REQUEST: + case SEC_OID_EXT_KEY_USAGE_SERVER_AUTH: + case SEC_OID_EXT_KEY_USAGE_CLIENT_AUTH: + case SEC_OID_EXT_KEY_USAGE_CODE_SIGN: + case SEC_OID_EXT_KEY_USAGE_EMAIL_PROTECT: + case SEC_OID_EXT_KEY_USAGE_TIME_STAMP: + + default: + defualt: + secu_PrintAny(out, tmpitem, "Data", level+1); + break; + } + + secu_Newline(out); + extensions++; + } + } +} + + +void +SECU_PrintName(FILE *out, CERTName *name, char *msg, int level) +{ + char *str; + + SECU_Indent(out, level); fprintf(out, "%s: ", msg); + + str = CERT_NameToAscii(name); + if (!str) + str = "!Invalid AVA!"; + fprintf(out, str); + + secu_Newline(out); +} + +void +printflags(char *trusts, unsigned int flags) +{ + if (flags & CERTDB_VALID_CA) + if (!(flags & CERTDB_TRUSTED_CA) && + !(flags & CERTDB_TRUSTED_CLIENT_CA)) + PORT_Strcat(trusts, "c"); + if (flags & CERTDB_VALID_PEER) + if (!(flags & CERTDB_TRUSTED)) + PORT_Strcat(trusts, "p"); + if (flags & CERTDB_TRUSTED_CA) + PORT_Strcat(trusts, "C"); + if (flags & CERTDB_TRUSTED_CLIENT_CA) + PORT_Strcat(trusts, "T"); + if (flags & CERTDB_TRUSTED) + PORT_Strcat(trusts, "P"); + if (flags & CERTDB_USER) + PORT_Strcat(trusts, "u"); + if (flags & CERTDB_SEND_WARN) + PORT_Strcat(trusts, "w"); + if (flags & CERTDB_INVISIBLE_CA) + PORT_Strcat(trusts, "I"); + if (flags & CERTDB_GOVT_APPROVED_CA) + PORT_Strcat(trusts, "G"); + return; +} + +/* callback for listing certs through pkcs11 */ +SECStatus +SECU_PrintCertNickname(CERTCertificate *cert, void *data) +{ + CERTCertTrust *trust; + FILE *out; + char trusts[30]; + char *name; + + PORT_Memset (trusts, 0, sizeof (trusts)); + out = (FILE *)data; + + name = cert->nickname; + if ( name == NULL ) { + name = cert->emailAddr; + } + if ( name == NULL ) { + name = "(NULL)"; + } + + trust = cert->trust; + if (trust) { + printflags(trusts, trust->sslFlags); + PORT_Strcat(trusts, ","); + printflags(trusts, trust->emailFlags); + PORT_Strcat(trusts, ","); + printflags(trusts, trust->objectSigningFlags); + } else { + PORT_Memcpy(trusts,",,",3); + } + fprintf(out, "%-60s %-5s\n", name, trusts); + + return (SECSuccess); +} + +int /* sometimes a PRErrorCode, other times a SECStatus. Sigh. */ +SECU_PrintCertificateRequest(FILE *out, SECItem *der, char *m, int level) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + CERTCertificateRequest *cr; + int rv = SEC_ERROR_NO_MEMORY; + + if (!arena) + return rv; + + /* Decode certificate request */ + cr = PORT_ArenaZNew(arena, CERTCertificateRequest); + if (!cr) + goto loser; + cr->arena = arena; + rv = SEC_QuickDERDecodeItem(arena, cr, + SEC_ASN1_GET(CERT_CertificateRequestTemplate), der); + if (rv) + goto loser; + + /* Pretty print it out */ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &cr->version, "Version", level+1); + SECU_PrintName(out, &cr->subject, "Subject", level+1); + rv = secu_PrintSubjectPublicKeyInfo(out, arena, &cr->subjectPublicKeyInfo, + "Subject Public Key Info", level+1); + if (rv) + goto loser; + if (cr->attributes) + secu_PrintAny(out, cr->attributes[0], "Attributes", level+1); + +loser: + PORT_FreeArena(arena, PR_FALSE); + return rv; +} + +int +SECU_PrintCertificate(FILE *out, SECItem *der, char *m, int level) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + CERTCertificate *c; + int rv = SEC_ERROR_NO_MEMORY; + int iv; + + if (!arena) + return rv; + + /* Decode certificate */ + c = PORT_ArenaZNew(arena, CERTCertificate); + if (!c) + goto loser; + c->arena = arena; + rv = SEC_ASN1DecodeItem(arena, c, + SEC_ASN1_GET(CERT_CertificateTemplate), der); + if (rv) + goto loser; + + /* Pretty print it out */ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + iv = c->version.len ? DER_GetInteger(&c->version) : 0; /* version is optional */ + SECU_Indent(out, level+1); fprintf(out, "%s: %d (0x%x)\n", "Version", iv + 1, iv); + + SECU_PrintInteger(out, &c->serialNumber, "Serial Number", level+1); + SECU_PrintAlgorithmID(out, &c->signature, "Signature Algorithm", level+1); + SECU_PrintName(out, &c->issuer, "Issuer", level+1); + secu_PrintValidity(out, &c->validity, "Validity", level+1); + SECU_PrintName(out, &c->subject, "Subject", level+1); + rv = secu_PrintSubjectPublicKeyInfo(out, arena, &c->subjectPublicKeyInfo, + "Subject Public Key Info", level+1); + if (rv) + goto loser; + SECU_PrintExtensions(out, c->extensions, "Signed Extensions", level+1); + SECU_PrintFingerprints(out, &c->derCert, "Fingerprint", level); +loser: + PORT_FreeArena(arena, PR_FALSE); + return rv; +} + +int +SECU_PrintPublicKey(FILE *out, SECItem *der, char *m, int level) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + SECKEYPublicKey key; + int rv = SEC_ERROR_NO_MEMORY; + + if (!arena) + return rv; + + PORT_Memset(&key, 0, sizeof(key)); + rv = SEC_ASN1DecodeItem(arena, &key, + SEC_ASN1_GET(SECKEY_RSAPublicKeyTemplate), der); + if (!rv) { + /* Pretty print it out */ + secu_PrintRSAPublicKey(out, &key, m, level); + } + + PORT_FreeArena(arena, PR_FALSE); + return rv; +} + +#ifdef HAVE_EPV_TEMPLATE +int +SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + SECKEYEncryptedPrivateKeyInfo key; + int rv = SEC_ERROR_NO_MEMORY; + + if (!arena) + return rv; + + PORT_Memset(&key, 0, sizeof(key)); + rv = SEC_ASN1DecodeItem(arena, &key, + SEC_ASN1_GET(SECKEY_EncryptedPrivateKeyInfoTemplate), der); + if (rv) + goto loser; + + /* Pretty print it out */ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintAlgorithmID(out, &key.algorithm, "Encryption Algorithm", + level+1); + SECU_PrintAsHex(out, &key.encryptedData, "Encrypted Data", level+1); +loser: + PORT_FreeArena(arena, PR_TRUE); + return rv; +} +#endif + +int +SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m, int level) +{ + unsigned char fingerprint[20]; + char *fpStr = NULL; + SECItem fpItem; + /* print MD5 fingerprint */ + memset(fingerprint, 0, sizeof fingerprint); + PK11_HashBuf(SEC_OID_MD5,fingerprint, derCert->data, derCert->len); + fpItem.data = fingerprint; + fpItem.len = MD5_LENGTH; + fpStr = CERT_Hexify(&fpItem, 1); + SECU_Indent(out, level); fprintf(out, "%s (MD5):\n", m); + SECU_Indent(out, level+1); fprintf(out, "%s\n", fpStr); + PORT_Free(fpStr); + fpStr = NULL; + /* print SHA1 fingerprint */ + memset(fingerprint, 0, sizeof fingerprint); + PK11_HashBuf(SEC_OID_SHA1,fingerprint, derCert->data, derCert->len); + fpItem.data = fingerprint; + fpItem.len = SHA1_LENGTH; + fpStr = CERT_Hexify(&fpItem, 1); + SECU_Indent(out, level); fprintf(out, "%s (SHA1):\n", m); + SECU_Indent(out, level+1); fprintf(out, "%s\n", fpStr); + PORT_Free(fpStr); + fprintf(out, "\n"); + return 0; +} + +/* +** PKCS7 Support +*/ + +/* forward declaration */ +static int +secu_PrintPKCS7ContentInfo(FILE *, SEC_PKCS7ContentInfo *, char *, int); + +/* +** secu_PrintPKCS7EncContent +** Prints a SEC_PKCS7EncryptedContentInfo (without decrypting it) +*/ +static void +secu_PrintPKCS7EncContent(FILE *out, SEC_PKCS7EncryptedContentInfo *src, + char *m, int level) +{ + if (src->contentTypeTag == NULL) + src->contentTypeTag = SECOID_FindOID(&(src->contentType)); + + SECU_Indent(out, level); + fprintf(out, "%s:\n", m); + SECU_Indent(out, level + 1); + fprintf(out, "Content Type: %s\n", + (src->contentTypeTag != NULL) ? src->contentTypeTag->desc + : "Unknown"); + SECU_PrintAlgorithmID(out, &(src->contentEncAlg), + "Content Encryption Algorithm", level+1); + SECU_PrintAsHex(out, &(src->encContent), + "Encrypted Content", level+1); +} + +/* +** secu_PrintRecipientInfo +** Prints a PKCS7RecipientInfo type +*/ +static void +secu_PrintRecipientInfo(FILE *out, SEC_PKCS7RecipientInfo *info, char *m, + int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(info->version), "Version", level + 1); + + SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer", + level + 1); + SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber), + "Serial Number", level + 1); + + /* Parse and display encrypted key */ + SECU_PrintAlgorithmID(out, &(info->keyEncAlg), + "Key Encryption Algorithm", level + 1); + SECU_PrintAsHex(out, &(info->encKey), "Encrypted Key", level + 1); +} + +/* +** secu_PrintSignerInfo +** Prints a PKCS7SingerInfo type +*/ +static void +secu_PrintSignerInfo(FILE *out, SEC_PKCS7SignerInfo *info, char *m, int level) +{ + SEC_PKCS7Attribute *attr; + int iv; + char om[100]; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(info->version), "Version", level + 1); + + SECU_PrintName(out, &(info->issuerAndSN->issuer), "Issuer", + level + 1); + SECU_PrintInteger(out, &(info->issuerAndSN->serialNumber), + "Serial Number", level + 1); + + SECU_PrintAlgorithmID(out, &(info->digestAlg), "Digest Algorithm", + level + 1); + + if (info->authAttr != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Authenticated Attributes:\n"); + iv = 0; + while ((attr = info->authAttr[iv++]) != NULL) { + sprintf(om, "Attribute (%d)", iv); + secu_PrintAttribute(out, attr, om, level + 2); + } + } + + /* Parse and display signature */ + SECU_PrintAlgorithmID(out, &(info->digestEncAlg), + "Digest Encryption Algorithm", level + 1); + SECU_PrintAsHex(out, &(info->encDigest), "Encrypted Digest", level + 1); + + if (info->unAuthAttr != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Unauthenticated Attributes:\n"); + iv = 0; + while ((attr = info->unAuthAttr[iv++]) != NULL) { + sprintf(om, "Attribute (%x)", iv); + secu_PrintAttribute(out, attr, om, level + 2); + } + } +} + +/* callers of this function must make sure that the CERTSignedCrl + from which they are extracting the CERTCrl has been fully-decoded. + Otherwise it will not have the entries even though the CRL may have + some */ + +void +SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, char *m, int level) +{ + CERTCrlEntry *entry; + int iv; + char om[100]; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintAlgorithmID(out, &(crl->signatureAlg), "Signature Algorithm", + level + 1); + SECU_PrintName(out, &(crl->name), "Name", level + 1); + SECU_PrintUTCTime(out, &(crl->lastUpdate), "Last Update", level + 1); + SECU_PrintUTCTime(out, &(crl->nextUpdate), "Next Update", level + 1); + + if (crl->entries != NULL) { + iv = 0; + while ((entry = crl->entries[iv++]) != NULL) { + sprintf(om, "Entry (%x):\n", iv); + SECU_Indent(out, level + 1); fprintf(out, om); + SECU_PrintInteger(out, &(entry->serialNumber), "Serial Number", + level + 2); + SECU_PrintUTCTime(out, &(entry->revocationDate), "Revocation Date", + level + 2); + SECU_PrintExtensions + (out, entry->extensions, "Signed CRL Entries Extensions", level + 1); + } + } + SECU_PrintExtensions + (out, crl->extensions, "Signed CRL Extension", level + 1); +} + +/* +** secu_PrintPKCS7Signed +** Pretty print a PKCS7 signed data type (up to version 1). +*/ +static int +secu_PrintPKCS7Signed(FILE *out, SEC_PKCS7SignedData *src, + const char *m, int level) +{ + SECAlgorithmID *digAlg; /* digest algorithms */ + SECItem *aCert; /* certificate */ + CERTSignedCrl *aCrl; /* certificate revocation list */ + SEC_PKCS7SignerInfo *sigInfo; /* signer information */ + int rv, iv; + char om[100]; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(src->version), "Version", level + 1); + + /* Parse and list digest algorithms (if any) */ + if (src->digestAlgorithms != NULL) { + SECU_Indent(out, level + 1); fprintf(out, "Digest Algorithm List:\n"); + iv = 0; + while ((digAlg = src->digestAlgorithms[iv++]) != NULL) { + sprintf(om, "Digest Algorithm (%x)", iv); + SECU_PrintAlgorithmID(out, digAlg, om, level + 2); + } + } + + /* Now for the content */ + rv = secu_PrintPKCS7ContentInfo(out, &(src->contentInfo), + "Content Information", level + 1); + if (rv != 0) + return rv; + + /* Parse and list certificates (if any) */ + if (src->rawCerts != NULL) { + SECU_Indent(out, level + 1); fprintf(out, "Certificate List:\n"); + iv = 0; + while ((aCert = src->rawCerts[iv++]) != NULL) { + sprintf(om, "Certificate (%x)", iv); + rv = SECU_PrintSignedData(out, aCert, om, level + 2, + SECU_PrintCertificate); + if (rv) + return rv; + } + } + + /* Parse and list CRL's (if any) */ + if (src->crls != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Signed Revocation Lists:\n"); + iv = 0; + while ((aCrl = src->crls[iv++]) != NULL) { + sprintf(om, "Signed Revocation List (%x)", iv); + SECU_Indent(out, level + 2); fprintf(out, "%s:\n", om); + SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, + "Signature Algorithm", level+3); + DER_ConvertBitString(&aCrl->signatureWrap.signature); + SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature", + level+3); + SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List", + level + 3); + } + } + + /* Parse and list signatures (if any) */ + if (src->signerInfos != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Signer Information List:\n"); + iv = 0; + while ((sigInfo = src->signerInfos[iv++]) != NULL) { + sprintf(om, "Signer Information (%x)", iv); + secu_PrintSignerInfo(out, sigInfo, om, level + 2); + } + } + + return 0; +} + +/* +** secu_PrintPKCS7Enveloped +** Pretty print a PKCS7 enveloped data type (up to version 1). +*/ +static void +secu_PrintPKCS7Enveloped(FILE *out, SEC_PKCS7EnvelopedData *src, + const char *m, int level) +{ + SEC_PKCS7RecipientInfo *recInfo; /* pointer for signer information */ + int iv; + char om[100]; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(src->version), "Version", level + 1); + + /* Parse and list recipients (this is not optional) */ + if (src->recipientInfos != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Recipient Information List:\n"); + iv = 0; + while ((recInfo = src->recipientInfos[iv++]) != NULL) { + sprintf(om, "Recipient Information (%x)", iv); + secu_PrintRecipientInfo(out, recInfo, om, level + 2); + } + } + + secu_PrintPKCS7EncContent(out, &src->encContentInfo, + "Encrypted Content Information", level + 1); +} + +/* +** secu_PrintPKCS7SignedEnveloped +** Pretty print a PKCS7 singed and enveloped data type (up to version 1). +*/ +static int +secu_PrintPKCS7SignedAndEnveloped(FILE *out, + SEC_PKCS7SignedAndEnvelopedData *src, + const char *m, int level) +{ + SECAlgorithmID *digAlg; /* pointer for digest algorithms */ + SECItem *aCert; /* pointer for certificate */ + CERTSignedCrl *aCrl; /* pointer for certificate revocation list */ + SEC_PKCS7SignerInfo *sigInfo; /* pointer for signer information */ + SEC_PKCS7RecipientInfo *recInfo; /* pointer for recipient information */ + int rv, iv; + char om[100]; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(src->version), "Version", level + 1); + + /* Parse and list recipients (this is not optional) */ + if (src->recipientInfos != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Recipient Information List:\n"); + iv = 0; + while ((recInfo = src->recipientInfos[iv++]) != NULL) { + sprintf(om, "Recipient Information (%x)", iv); + secu_PrintRecipientInfo(out, recInfo, om, level + 2); + } + } + + /* Parse and list digest algorithms (if any) */ + if (src->digestAlgorithms != NULL) { + SECU_Indent(out, level + 1); fprintf(out, "Digest Algorithm List:\n"); + iv = 0; + while ((digAlg = src->digestAlgorithms[iv++]) != NULL) { + sprintf(om, "Digest Algorithm (%x)", iv); + SECU_PrintAlgorithmID(out, digAlg, om, level + 2); + } + } + + secu_PrintPKCS7EncContent(out, &src->encContentInfo, + "Encrypted Content Information", level + 1); + + /* Parse and list certificates (if any) */ + if (src->rawCerts != NULL) { + SECU_Indent(out, level + 1); fprintf(out, "Certificate List:\n"); + iv = 0; + while ((aCert = src->rawCerts[iv++]) != NULL) { + sprintf(om, "Certificate (%x)", iv); + rv = SECU_PrintSignedData(out, aCert, om, level + 2, + SECU_PrintCertificate); + if (rv) + return rv; + } + } + + /* Parse and list CRL's (if any) */ + if (src->crls != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Signed Revocation Lists:\n"); + iv = 0; + while ((aCrl = src->crls[iv++]) != NULL) { + sprintf(om, "Signed Revocation List (%x)", iv); + SECU_Indent(out, level + 2); fprintf(out, "%s:\n", om); + SECU_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, + "Signature Algorithm", level+3); + DER_ConvertBitString(&aCrl->signatureWrap.signature); + SECU_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature", + level+3); + SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List", + level + 3); + } + } + + /* Parse and list signatures (if any) */ + if (src->signerInfos != NULL) { + SECU_Indent(out, level + 1); + fprintf(out, "Signer Information List:\n"); + iv = 0; + while ((sigInfo = src->signerInfos[iv++]) != NULL) { + sprintf(om, "Signer Information (%x)", iv); + secu_PrintSignerInfo(out, sigInfo, om, level + 2); + } + } + + return 0; +} + +int +SECU_PrintCrl (FILE *out, SECItem *der, char *m, int level) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + CERTCrl *c = NULL; + int rv = SEC_ERROR_NO_MEMORY; + + if (!arena) + return rv; + do { + /* Decode CRL */ + c = PORT_ArenaZNew(arena, CERTCrl); + if (!c) + break; + + rv = SEC_ASN1DecodeItem(arena, c, SEC_ASN1_GET(CERT_CrlTemplate), der); + if (rv != SECSuccess) + break; + SECU_PrintCRLInfo (out, c, m, level); + } while (0); + PORT_FreeArena (arena, PR_FALSE); + return rv; +} + + +/* +** secu_PrintPKCS7Encrypted +** Pretty print a PKCS7 encrypted data type (up to version 1). +*/ +static void +secu_PrintPKCS7Encrypted(FILE *out, SEC_PKCS7EncryptedData *src, + const char *m, int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(src->version), "Version", level + 1); + + secu_PrintPKCS7EncContent(out, &src->encContentInfo, + "Encrypted Content Information", level + 1); +} + +/* +** secu_PrintPKCS7Digested +** Pretty print a PKCS7 digested data type (up to version 1). +*/ +static void +secu_PrintPKCS7Digested(FILE *out, SEC_PKCS7DigestedData *src, + const char *m, int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_PrintInteger(out, &(src->version), "Version", level + 1); + + SECU_PrintAlgorithmID(out, &src->digestAlg, "Digest Algorithm", + level + 1); + secu_PrintPKCS7ContentInfo(out, &src->contentInfo, "Content Information", + level + 1); + SECU_PrintAsHex(out, &src->digest, "Digest", level + 1); +} + +/* +** secu_PrintPKCS7ContentInfo +** Takes a SEC_PKCS7ContentInfo type and sends the contents to the +** appropriate function +*/ +static int +secu_PrintPKCS7ContentInfo(FILE *out, SEC_PKCS7ContentInfo *src, + char *m, int level) +{ + const char *desc; + SECOidTag kind; + int rv; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + level++; + + if (src->contentTypeTag == NULL) + src->contentTypeTag = SECOID_FindOID(&(src->contentType)); + + if (src->contentTypeTag == NULL) { + desc = "Unknown"; + kind = SEC_OID_PKCS7_DATA; + } else { + desc = src->contentTypeTag->desc; + kind = src->contentTypeTag->offset; + } + + if (src->content.data == NULL) { + SECU_Indent(out, level); fprintf(out, "%s:\n", desc); + level++; + SECU_Indent(out, level); fprintf(out, "<no content>\n"); + return 0; + } + + rv = 0; + switch (kind) { + case SEC_OID_PKCS7_SIGNED_DATA: /* Signed Data */ + rv = secu_PrintPKCS7Signed(out, src->content.signedData, desc, level); + break; + + case SEC_OID_PKCS7_ENVELOPED_DATA: /* Enveloped Data */ + secu_PrintPKCS7Enveloped(out, src->content.envelopedData, desc, level); + break; + + case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: /* Signed and Enveloped */ + rv = secu_PrintPKCS7SignedAndEnveloped(out, + src->content.signedAndEnvelopedData, + desc, level); + break; + + case SEC_OID_PKCS7_DIGESTED_DATA: /* Digested Data */ + secu_PrintPKCS7Digested(out, src->content.digestedData, desc, level); + break; + + case SEC_OID_PKCS7_ENCRYPTED_DATA: /* Encrypted Data */ + secu_PrintPKCS7Encrypted(out, src->content.encryptedData, desc, level); + break; + + default: + SECU_PrintAsHex(out, src->content.data, desc, level); + break; + } + + return rv; +} + +/* +** SECU_PrintPKCS7ContentInfo +** Decode and print any major PKCS7 data type (up to version 1). +*/ +int +SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, char *m, int level) +{ + SEC_PKCS7ContentInfo *cinfo; + int rv; + + cinfo = SEC_PKCS7DecodeItem(der, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + if (cinfo != NULL) { + /* Send it to recursive parsing and printing module */ + rv = secu_PrintPKCS7ContentInfo(out, cinfo, m, level); + SEC_PKCS7DestroyContentInfo(cinfo); + } else { + rv = -1; + } + + return rv; +} + +/* +** End of PKCS7 functions +*/ + +void +printFlags(FILE *out, unsigned int flags, int level) +{ + if ( flags & CERTDB_VALID_PEER ) { + SECU_Indent(out, level); fprintf(out, "Valid Peer\n"); + } + if ( flags & CERTDB_TRUSTED ) { + SECU_Indent(out, level); fprintf(out, "Trusted\n"); + } + if ( flags & CERTDB_SEND_WARN ) { + SECU_Indent(out, level); fprintf(out, "Warn When Sending\n"); + } + if ( flags & CERTDB_VALID_CA ) { + SECU_Indent(out, level); fprintf(out, "Valid CA\n"); + } + if ( flags & CERTDB_TRUSTED_CA ) { + SECU_Indent(out, level); fprintf(out, "Trusted CA\n"); + } + if ( flags & CERTDB_NS_TRUSTED_CA ) { + SECU_Indent(out, level); fprintf(out, "Netscape Trusted CA\n"); + } + if ( flags & CERTDB_USER ) { + SECU_Indent(out, level); fprintf(out, "User\n"); + } + if ( flags & CERTDB_TRUSTED_CLIENT_CA ) { + SECU_Indent(out, level); fprintf(out, "Trusted Client CA\n"); + } +#ifdef DEBUG + if ( flags & CERTDB_GOVT_APPROVED_CA ) { + SECU_Indent(out, level); fprintf(out, "Step-up\n"); + } +#endif /* DEBUG */ +} + +void +SECU_PrintTrustFlags(FILE *out, CERTCertTrust *trust, char *m, int level) +{ + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + SECU_Indent(out, level+1); fprintf(out, "SSL Flags:\n"); + printFlags(out, trust->sslFlags, level+2); + SECU_Indent(out, level+1); fprintf(out, "Email Flags:\n"); + printFlags(out, trust->emailFlags, level+2); + SECU_Indent(out, level+1); fprintf(out, "Object Signing Flags:\n"); + printFlags(out, trust->objectSigningFlags, level+2); +} + +int SECU_PrintSignedData(FILE *out, SECItem *der, char *m, + int level, SECU_PPFunc inner) +{ + PRArenaPool *arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + CERTSignedData *sd; + int rv = SEC_ERROR_NO_MEMORY; + + if (!arena) + return rv; + + /* Strip off the signature */ + sd = PORT_ArenaZNew(arena, CERTSignedData); + if (!sd) + goto loser; + + rv = SEC_ASN1DecodeItem(arena, sd, SEC_ASN1_GET(CERT_SignedDataTemplate), + der); + if (rv) + goto loser; + + SECU_Indent(out, level); fprintf(out, "%s:\n", m); + rv = (*inner)(out, &sd->data, "Data", level+1); + if (rv) + goto loser; + + SECU_PrintAlgorithmID(out, &sd->signatureAlgorithm, "Signature Algorithm", + level+1); + DER_ConvertBitString(&sd->signature); + SECU_PrintAsHex(out, &sd->signature, "Signature", level+1); +loser: + PORT_FreeArena(arena, PR_FALSE); + return rv; + +} + + +#ifdef AIX +int _OS_SELECT (int nfds, void *readfds, void *writefds, + void *exceptfds, struct timeval *timeout) { + return select (nfds,readfds,writefds,exceptfds,timeout); +} +#endif + +SECItem * +SECU_GetPBEPassword(void *arg) +{ + char *p = NULL; + SECItem *pwitem = NULL; + + p = SECU_GetPasswordString(arg,"Password: "); + + /* NOTE: This function is obviously unfinished. */ + + if ( pwitem == NULL ) { + fprintf(stderr, "Error hashing password\n"); + return NULL; + } + + return pwitem; +} + +SECStatus +SECU_ParseCommandLine(int argc, char **argv, char *progName, secuCommand *cmd) +{ + PRBool found; + PLOptState *optstate; + PLOptStatus status; + char *optstring; + int i, j; + + optstring = (char *)malloc(cmd->numCommands + 2*cmd->numOptions); + j = 0; + + for (i=0; i<cmd->numCommands; i++) { + optstring[j++] = cmd->commands[i].flag; + } + for (i=0; i<cmd->numOptions; i++) { + optstring[j++] = cmd->options[i].flag; + if (cmd->options[i].needsArg) + optstring[j++] = ':'; + } + optstring[j] = '\0'; + optstate = PL_CreateOptState(argc, argv, optstring); + + /* Parse command line arguments */ + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + + /* Wasn't really an option, just standalone arg. */ + if (optstate->option == '\0') + continue; + + found = PR_FALSE; + + for (i=0; i<cmd->numCommands; i++) { + if (cmd->commands[i].flag == optstate->option) { + cmd->commands[i].activated = PR_TRUE; + if (optstate->value) { + cmd->commands[i].arg = (char *)optstate->value; + } + found = PR_TRUE; + break; + } + } + + if (found) + continue; + + for (i=0; i<cmd->numOptions; i++) { + if (cmd->options[i].flag == optstate->option) { + cmd->options[i].activated = PR_TRUE; + if (optstate->value) { + cmd->options[i].arg = (char *)optstate->value; + } + found = PR_TRUE; + break; + } + } + + if (!found) + return SECFailure; + } + if (status == PL_OPT_BAD) + return SECFailure; + return SECSuccess; +} + +char * +SECU_GetOptionArg(secuCommand *cmd, int optionNum) +{ + if (optionNum < 0 || optionNum >= cmd->numOptions) + return NULL; + if (cmd->options[optionNum].activated) + return PL_strdup(cmd->options[optionNum].arg); + else + return NULL; +} + +static char SECUErrorBuf[64]; + +char * +SECU_ErrorStringRaw(int16 err) +{ + if (err == 0) + sprintf(SECUErrorBuf, ""); + else if (err == SEC_ERROR_BAD_DATA) + sprintf(SECUErrorBuf, "Bad data"); + else if (err == SEC_ERROR_BAD_DATABASE) + sprintf(SECUErrorBuf, "Problem with database"); + else if (err == SEC_ERROR_BAD_DER) + sprintf(SECUErrorBuf, "Problem with DER"); + else if (err == SEC_ERROR_BAD_KEY) + sprintf(SECUErrorBuf, "Problem with key"); + else if (err == SEC_ERROR_BAD_PASSWORD) + sprintf(SECUErrorBuf, "Incorrect password"); + else if (err == SEC_ERROR_BAD_SIGNATURE) + sprintf(SECUErrorBuf, "Bad signature"); + else if (err == SEC_ERROR_EXPIRED_CERTIFICATE) + sprintf(SECUErrorBuf, "Expired certificate"); + else if (err == SEC_ERROR_EXTENSION_VALUE_INVALID) + sprintf(SECUErrorBuf, "Invalid extension value"); + else if (err == SEC_ERROR_INPUT_LEN) + sprintf(SECUErrorBuf, "Problem with input length"); + else if (err == SEC_ERROR_INVALID_ALGORITHM) + sprintf(SECUErrorBuf, "Invalid algorithm"); + else if (err == SEC_ERROR_INVALID_ARGS) + sprintf(SECUErrorBuf, "Invalid arguments"); + else if (err == SEC_ERROR_INVALID_AVA) + sprintf(SECUErrorBuf, "Invalid AVA"); + else if (err == SEC_ERROR_INVALID_TIME) + sprintf(SECUErrorBuf, "Invalid time"); + else if (err == SEC_ERROR_IO) + sprintf(SECUErrorBuf, "Security I/O error"); + else if (err == SEC_ERROR_LIBRARY_FAILURE) + sprintf(SECUErrorBuf, "Library failure"); + else if (err == SEC_ERROR_NO_MEMORY) + sprintf(SECUErrorBuf, "Out of memory"); + else if (err == SEC_ERROR_OLD_CRL) + sprintf(SECUErrorBuf, "CRL is older than the current one"); + else if (err == SEC_ERROR_OUTPUT_LEN) + sprintf(SECUErrorBuf, "Problem with output length"); + else if (err == SEC_ERROR_UNKNOWN_ISSUER) + sprintf(SECUErrorBuf, "Unknown issuer"); + else if (err == SEC_ERROR_UNTRUSTED_CERT) + sprintf(SECUErrorBuf, "Untrusted certificate"); + else if (err == SEC_ERROR_UNTRUSTED_ISSUER) + sprintf(SECUErrorBuf, "Untrusted issuer"); + else if (err == SSL_ERROR_BAD_CERTIFICATE) + sprintf(SECUErrorBuf, "Bad certificate"); + else if (err == SSL_ERROR_BAD_CLIENT) + sprintf(SECUErrorBuf, "Bad client"); + else if (err == SSL_ERROR_BAD_SERVER) + sprintf(SECUErrorBuf, "Bad server"); + else if (err == SSL_ERROR_EXPORT_ONLY_SERVER) + sprintf(SECUErrorBuf, "Export only server"); + else if (err == SSL_ERROR_NO_CERTIFICATE) + sprintf(SECUErrorBuf, "No certificate"); + else if (err == SSL_ERROR_NO_CYPHER_OVERLAP) + sprintf(SECUErrorBuf, "No cypher overlap"); + else if (err == SSL_ERROR_UNSUPPORTED_CERTIFICATE_TYPE) + sprintf(SECUErrorBuf, "Unsupported certificate type"); + else if (err == SSL_ERROR_UNSUPPORTED_VERSION) + sprintf(SECUErrorBuf, "Unsupported version"); + else if (err == SSL_ERROR_US_ONLY_SERVER) + sprintf(SECUErrorBuf, "U.S. only server"); + else if (err == PR_IO_ERROR) + sprintf(SECUErrorBuf, "I/O error"); + + else if (err == SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE) + sprintf (SECUErrorBuf, "Expired Issuer Certificate"); + else if (err == SEC_ERROR_REVOKED_CERTIFICATE) + sprintf (SECUErrorBuf, "Revoked certificate"); + else if (err == SEC_ERROR_NO_KEY) + sprintf (SECUErrorBuf, "No private key in database for this cert"); + else if (err == SEC_ERROR_CERT_NOT_VALID) + sprintf (SECUErrorBuf, "Certificate is not valid"); + else if (err == SEC_ERROR_EXTENSION_NOT_FOUND) + sprintf (SECUErrorBuf, "Certificate extension was not found"); + else if (err == SEC_ERROR_EXTENSION_VALUE_INVALID) + sprintf (SECUErrorBuf, "Certificate extension value invalid"); + else if (err == SEC_ERROR_CA_CERT_INVALID) + sprintf (SECUErrorBuf, "Issuer certificate is invalid"); + else if (err == SEC_ERROR_CERT_USAGES_INVALID) + sprintf (SECUErrorBuf, "Certificate usages is invalid"); + else if (err == SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION) + sprintf (SECUErrorBuf, "Certificate has unknown critical extension"); + else if (err == SEC_ERROR_PKCS7_BAD_SIGNATURE) + sprintf (SECUErrorBuf, "Bad PKCS7 signature"); + else if (err == SEC_ERROR_INADEQUATE_KEY_USAGE) + sprintf (SECUErrorBuf, "Certificate not approved for this operation"); + else if (err == SEC_ERROR_INADEQUATE_CERT_TYPE) + sprintf (SECUErrorBuf, "Certificate not approved for this operation"); + + return SECUErrorBuf; +} + +char * +SECU_ErrorString(int16 err) +{ + char *error_string; + + *SECUErrorBuf = 0; + SECU_ErrorStringRaw (err); + + if (*SECUErrorBuf == 0) { + error_string = SECU_GetString(err); + if (error_string == NULL || *error_string == '\0') + sprintf(SECUErrorBuf, "No error string found for %d.", err); + else + return error_string; + } + + return SECUErrorBuf; +} + + +void +SECU_PrintPRandOSError(char *progName) +{ + char buffer[513]; + PRInt32 errLen = PR_GetErrorTextLength(); + if (errLen > 0 && errLen < sizeof buffer) { + PR_GetErrorText(buffer); + } + SECU_PrintError(progName, "NSS_Initialize failed"); + if (errLen > 0 && errLen < sizeof buffer) { + PR_fprintf(PR_STDERR, "\t%s\n", buffer); + } +} diff --git a/security/nss/cmd/lib/secutil.h b/security/nss/cmd/lib/secutil.h new file mode 100644 index 000000000..69d9865d3 --- /dev/null +++ b/security/nss/cmd/lib/secutil.h @@ -0,0 +1,327 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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_UTIL_H_ +#define _SEC_UTIL_H_ + +#include "seccomon.h" +#include "secitem.h" +#include "prerror.h" +#include "base64.h" +#include "key.h" +#include "secpkcs7.h" +#include "secasn1.h" +#include "secder.h" +#include <stdio.h> + +#define SEC_CT_PRIVATE_KEY "private-key" +#define SEC_CT_PUBLIC_KEY "public-key" +#define SEC_CT_CERTIFICATE "certificate" +#define SEC_CT_CERTIFICATE_REQUEST "certificate-request" +#define SEC_CT_PKCS7 "pkcs7" +#define SEC_CT_CRL "crl" + +#define NS_CERTREQ_HEADER "-----BEGIN NEW CERTIFICATE REQUEST-----" +#define NS_CERTREQ_TRAILER "-----END NEW CERTIFICATE REQUEST-----" + +#define NS_CERT_HEADER "-----BEGIN CERTIFICATE-----" +#define NS_CERT_TRAILER "-----END CERTIFICATE-----" + +/* From libsec/pcertdb.c --- it's not declared in sec.h */ +extern SECStatus SEC_AddPermCertificate(CERTCertDBHandle *handle, + SECItem *derCert, char *nickname, CERTCertTrust *trust); + + +#ifdef SECUTIL_NEW +typedef int (*SECU_PPFunc)(PRFileDesc *out, SECItem *item, + char *msg, int level); +#else +typedef int (*SECU_PPFunc)(FILE *out, SECItem *item, char *msg, int level); +#endif + +typedef struct { + enum { + PW_NONE = 0, + PW_FROMFILE = 1, + PW_PLAINTEXT = 2 + } source; + char *data; +} secuPWData; + +/* +** Change a password on a token, or initialize a token with a password +** if it does not already have one. +** Use passwd to send the password in plaintext, pwFile to specify a +** file containing the password, or NULL for both to prompt the user. +*/ +SECStatus SECU_ChangePW(PK11SlotInfo *slot, char *passwd, char *pwFile); + +/* These were stolen from the old sec.h... */ +/* +** Check a password for legitimacy. Passwords must be at least 8 +** characters long and contain one non-alphabetic. Return DSTrue if the +** password is ok, DSFalse otherwise. +*/ +extern PRBool SEC_CheckPassword(char *password); + +/* +** Blind check of a password. Complement to SEC_CheckPassword which +** ignores length and content type, just retuning DSTrue is the password +** exists, DSFalse if NULL +*/ +extern PRBool SEC_BlindCheckPassword(char *password); + +/* +** Get a password. +** First prompt with "msg" on "out", then read the password from "in". +** The password is then checked using "chkpw". +*/ +extern char *SEC_GetPassword(FILE *in, FILE *out, char *msg, + PRBool (*chkpw)(char *)); + +char *SECU_FilePasswd(PK11SlotInfo *slot, PRBool retry, void *arg); + +char *SECU_GetPasswordString(void *arg, char *prompt); + +/* +** Write a dongle password. +** Uses MD5 to hash constant system data (hostname, etc.), and then +** creates RC4 key to encrypt a password "pw" into a file "fd". +*/ +extern SECStatus SEC_WriteDongleFile(int fd, char *pw); + +/* +** Get a dongle password. +** Uses MD5 to hash constant system data (hostname, etc.), and then +** creates RC4 key to decrypt and return a password from file "fd". +*/ +extern char *SEC_ReadDongleFile(int fd); + + +/* End stolen headers */ + +/* Just sticks the two strings together with a / if needed */ +char *SECU_AppendFilenameToDir(char *dir, char *filename); + +/* Returns result of getenv("SSL_DIR") or NULL */ +extern char *SECU_DefaultSSLDir(void); + +/* +** Should be called once during initialization to set the default +** directory for looking for cert.db, key.db, and cert-nameidx.db files +** Removes trailing '/' in 'base' +** If 'base' is NULL, defaults to set to .netscape in home directory. +*/ +extern char *SECU_ConfigDirectory(const char* base); + +/* +** Basic callback function for SSL_GetClientAuthDataHook +*/ +extern int +SECU_GetClientAuthData(void *arg, PRFileDesc *fd, + struct CERTDistNamesStr *caNames, + struct CERTCertificateStr **pRetCert, + struct SECKEYPrivateKeyStr **pRetKey); + +/* print out an error message */ +extern void SECU_PrintError(char *progName, char *msg, ...); + +/* print out a system error message */ +extern void SECU_PrintSystemError(char *progName, char *msg, ...); + +/* Return informative error string */ +extern const char * SECU_Strerror(PRErrorCode errNum); + +/* Read the contents of a file into a SECItem */ +extern SECStatus SECU_FileToItem(SECItem *dst, PRFileDesc *src); +extern SECStatus SECU_TextFileToItem(SECItem *dst, PRFileDesc *src); + +/* Read in a DER from a file, may be ascii */ +extern SECStatus +SECU_ReadDERFromFile(SECItem *der, PRFileDesc *inFile, PRBool ascii); + +/* Indent based on "level" */ +extern void SECU_Indent(FILE *out, int level); + +/* Print integer value and hex */ +extern void SECU_PrintInteger(FILE *out, SECItem *i, char *m, int level); + +/* Print ObjectIdentifier symbolically */ +extern void SECU_PrintObjectID(FILE *out, SECItem *oid, char *m, int level); + +/* Print AlgorithmIdentifier symbolically */ +extern void SECU_PrintAlgorithmID(FILE *out, SECAlgorithmID *a, char *m, + int level); + +/* Print SECItem as hex */ +extern void SECU_PrintAsHex(FILE *out, SECItem *i, const char *m, int level); + +/* dump a buffer in hex and ASCII */ +extern void SECU_PrintBuf(FILE *out, const char *msg, const void *vp, int len); + +/* + * Format and print the UTC Time "t". If the tag message "m" is not NULL, + * do indent formatting based on "level" and add a newline afterward; + * otherwise just print the formatted time string only. + */ +extern void SECU_PrintUTCTime(FILE *out, SECItem *t, char *m, int level); + +/* + * Format and print the Generalized Time "t". If the tag message "m" + * is not NULL, * do indent formatting based on "level" and add a newline + * afterward; otherwise just print the formatted time string only. + */ +extern void SECU_PrintGeneralizedTime(FILE *out, SECItem *t, char *m, + int level); + +/* callback for listing certs through pkcs11 */ +extern SECStatus SECU_PrintCertNickname(CERTCertificate *cert, void *data); + +/* Dump all certificate nicknames in a database */ +extern SECStatus +SECU_PrintCertificateNames(CERTCertDBHandle *handle, PRFileDesc* out, + PRBool sortByName, PRBool sortByTrust); + +/* See if nickname already in database. Return 1 true, 0 false, -1 error */ +int SECU_CheckCertNameExists(CERTCertDBHandle *handle, char *nickname); + +/* Dump contents of cert req */ +extern int SECU_PrintCertificateRequest(FILE *out, SECItem *der, char *m, + int level); + +/* Dump contents of certificate */ +extern int SECU_PrintCertificate(FILE *out, SECItem *der, char *m, int level); + +/* print trust flags on a cert */ +extern void SECU_PrintTrustFlags(FILE *out, CERTCertTrust *trust, char *m, int level); + +/* Dump contents of public key */ +extern int SECU_PrintPublicKey(FILE *out, SECItem *der, char *m, int level); + +#ifdef HAVE_EPV_TEMPLATE +/* Dump contents of private key */ +extern int SECU_PrintPrivateKey(FILE *out, SECItem *der, char *m, int level); +#endif + +/* Print the MD5 and SHA1 fingerprints of a cert */ +extern int SECU_PrintFingerprints(FILE *out, SECItem *derCert, char *m, + int level); + +/* Pretty-print any PKCS7 thing */ +extern int SECU_PrintPKCS7ContentInfo(FILE *out, SECItem *der, char *m, + int level); + +/* Init PKCS11 stuff */ +extern SECStatus SECU_PKCS11Init(PRBool readOnly); + +/* Dump contents of signed data */ +extern int SECU_PrintSignedData(FILE *out, SECItem *der, char *m, int level, + SECU_PPFunc inner); + +extern int SECU_PrintCrl(FILE *out, SECItem *der, char *m, int level); + +extern void +SECU_PrintCRLInfo(FILE *out, CERTCrl *crl, char *m, int level); + +extern void SECU_PrintExtensions(FILE *out, CERTCertExtension **extensions, + char *msg, int level); + +extern void SECU_PrintName(FILE *out, CERTName *name, char *msg, int level); + +#ifdef SECU_GetPassword +/* Convert a High public Key to a Low public Key */ +extern SECKEYLowPublicKey *SECU_ConvHighToLow(SECKEYPublicKey *pubHighKey); +#endif + +extern SECItem *SECU_GetPBEPassword(void *arg); + +extern char *SECU_GetModulePassword(PK11SlotInfo *slot, PRBool retry, void *arg); + +extern SECStatus DER_PrettyPrint(FILE *out, SECItem *it, PRBool raw); +extern void SEC_Init(void); + +extern char *SECU_SECModDBName(void); + +extern void SECU_PrintPRandOSError(char *progName); + +/* + * + * Utilities for parsing security tools command lines + * + */ + +/* A single command flag */ +typedef struct { + char flag; + PRBool needsArg; + char *arg; + PRBool activated; +} secuCommandFlag; + +/* A full array of command/option flags */ +typedef struct +{ + int numCommands; + int numOptions; + + secuCommandFlag *commands; + secuCommandFlag *options; +} secuCommand; + +/* fill the "arg" and "activated" fields for each flag */ +SECStatus +SECU_ParseCommandLine(int argc, char **argv, char *progName, secuCommand *cmd); +char * +SECU_GetOptionArg(secuCommand *cmd, int optionNum); + +/* + * + * Error messaging + * + */ + +/* Return informative error string */ +char *SECU_ErrorString(int16 err); + +/* Return informative error string. Does not call XP_GetString */ +char *SECU_ErrorStringRaw(int16 err); + +void printflags(char *trusts, unsigned int flags); + +#ifndef XP_UNIX +extern int ffs(unsigned int i); +#endif + +#include "secerr.h" +#include "sslerr.h" + +#endif /* _SEC_UTIL_H_ */ diff --git a/security/nss/cmd/makefile.inc b/security/nss/cmd/makefile.inc new file mode 100644 index 000000000..029576e7c --- /dev/null +++ b/security/nss/cmd/makefile.inc @@ -0,0 +1,84 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +INCLUDES += \ + -I$(DEPTH)/security/lib/cert \ + -I$(DEPTH)/security/lib/key \ + -I$(DEPTH)/security/lib/util \ + -I../include \ + $(NULL) + + +# For the time being, sec stuff is export only +# US_FLAGS = -DEXPORT_VERSION -DUS_VERSION + +US_FLAGS = -DEXPORT_VERSION +EXPORT_FLAGS = -DEXPORT_VERSION + +BASE_LIBS = \ + $(DIST)/lib/libdbm.a \ + $(DIST)/lib/libxp.a \ + $(DIST)/lib/libnspr21.a \ + $(NULL) + + +#There is a circular dependancy in security/lib, and here is a gross fix +SEC_LIBS = \ + $(DIST)/lib/libsecnav.a \ + $(DIST)/lib/libssl.a \ + $(DIST)/lib/libpkcs7.a \ + $(DIST)/lib/libcert.a \ + $(DIST)/lib/libkey.a \ + $(DIST)/lib/libsecmod.a \ + $(DIST)/lib/libcrypto.a \ + $(DIST)/lib/libsecutil.a \ + $(DIST)/lib/libssl.a \ + $(DIST)/lib/libpkcs7.a \ + $(DIST)/lib/libcert.a \ + $(DIST)/lib/libkey.a \ + $(DIST)/lib/libsecmod.a \ + $(DIST)/lib/libcrypto.a \ + $(DIST)/lib/libsecutil.a \ + $(DIST)/lib/libhash.a \ + $(NULL) + +MYLIBDIR= ../lib/$(OBJDIR) +MYLIB = $(MYLIBDIR)/libsectool.a + +US_LIBS = $(MYLIB) $(SEC_LIBS) $(BASE_LIBS) $(MYLIB) $(BASE_LIBS) +EX_LIBS = $(MYLIB) $(SEC_LIBS) $(BASE_LIBS) $(MYLIB) $(BASE_LIBS) + +# this hack is necessary because rules.mk doesn't put anything like $(LIBS) +# on the link command line (!?!?!?!) +LDFLAGS += $(EX_LIBS) + diff --git a/security/nss/cmd/makefile.win b/security/nss/cmd/makefile.win new file mode 100644 index 000000000..5e506590b --- /dev/null +++ b/security/nss/cmd/makefile.win @@ -0,0 +1,48 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +VERBOSE = 1 +include <manifest.mn> + +include <$(DEPTH)\config\config.mak> + +include <$(DEPTH)\config\rules.mak> + +objs: $(OBJS) + +programs: $(PROGRAM) + +syms: + @echo "OBJS is $(OBJS)" + @echo "INCS is $(INCS)" + diff --git a/security/nss/cmd/makepqg/Makefile b/security/nss/cmd/makepqg/Makefile new file mode 100644 index 000000000..36bf774fb --- /dev/null +++ b/security/nss/cmd/makepqg/Makefile @@ -0,0 +1,77 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + + diff --git a/security/nss/cmd/makepqg/makefile.win b/security/nss/cmd/makepqg/makefile.win new file mode 100644 index 000000000..462448d73 --- /dev/null +++ b/security/nss/cmd/makepqg/makefile.win @@ -0,0 +1,156 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +VERBOSE = 1 +include <manifest.mn> + +PROGRAM = makepqg +PROGRAM = $(OBJDIR)\$(PROGRAM).exe + +include <$(DEPTH)\config\config.mak> + + +# let manifest generate C_OBJS, it will prepend ./$(OBJDIR)/ +# rules.mak will append C_OBJS onto OBJS. +# OBJS = $(CSRCS:.c=.obj) + +# include files are looked for in $LINCS and $INCS. +# $LINCS is in manifest.mnw, computed from REQUIRES= +INCS = $(INCS) \ + -I$(DEPTH)/security/lib/cert \ + -I$(DEPTH)/security/lib/crypto \ + -I../include \ + $(NULL) + +IGNORE_ME = \ + -I$(DEPTH)/security/lib/key \ + -I$(DEPTH)/security/lib/util \ + + +WINFE = $(DEPTH)/cmd/winfe/mkfiles$(MOZ_BITS)/x86Dbg + +# these files are the content of libdbm +DBM_LIB = \ + $(WINFE)/DB.obj \ + $(WINFE)/HASH.obj \ + $(WINFE)/H_BIGKEY.obj \ + $(WINFE)/H_PAGE.obj \ + $(WINFE)/H_LOG2.obj \ + $(WINFE)/H_FUNC.obj \ + $(WINFE)/HASH_BUF.obj \ + $(NULL) + +MOZ_LIBS = \ + $(WINFE)/ALLXPSTR.obj \ + $(WINFE)/XP_ERROR.obj \ + $(WINFE)/XPASSERT.obj \ + $(WINFE)/XP_REG.obj \ + $(WINFE)/XP_TRACE.obj \ + $(DBM_LIB) \ + $(WINFE)/XP_STR.obj \ + $(WINFE)/MKTEMP.obj \ + $(NULL) + +SEC_LIBS = \ + $(DIST)/lib/cert$(MOZ_BITS).lib \ + $(DIST)/lib/crypto$(MOZ_BITS).lib \ + $(DIST)/lib/hash$(MOZ_BITS).lib \ + $(DIST)/lib/key$(MOZ_BITS).lib \ + $(DIST)/lib/pkcs7$(MOZ_BITS).lib \ + $(DIST)/lib/secmod$(MOZ_BITS).lib \ + $(DIST)/lib/secutl$(MOZ_BITS).lib \ + $(DIST)/lib/ssl$(MOZ_BITS).lib \ + $(NULL) + +LLFLAGS = $(LLFLAGS) \ + ../lib/$(OBJDIR)/sectool$(MOZ_BITS).lib \ + $(SEC_LIBS) \ + $(MOZ_LIBS) \ + $(DEPTH)/nspr/src/$(OBJDIR)/getopt.obj \ + $(LIBNSPR) \ + $(NULL) + + +# awt3240.lib # brpref32.lib # cert32.lib +# crypto32.lib # dllcom.lib # editor32.lib +# edpref32.lib # edtplug.lib # font.lib +# hash32.lib # htmldg32.lib # img32.lib +# javart32.lib # jbn3240.lib # jdb3240.lib +# jmc.lib # jpeg3240.lib # jpw3240.lib +# jrt3240.lib # js3240.lib # jsd3240.lib +# key32.lib # libapplet32.lib # libnjs32.lib +# libnsc32.lib # libreg32.lib # mm3240.lib +# mnpref32.lib # netcst32.lib # nsdlg32.lib +# nsldap32.lib # nsldaps32.lib # nsn32.lib +# pkcs1232.lib # pkcs732.lib # pr3240.lib +# prefui32.lib # prefuuid.lib # secmod32.lib +# secnav32.lib # secutl32.lib # softup32.lib +# sp3240.lib # ssl32.lib # uni3200.lib +# unicvt32.lib # win32md.lib # winfont.lib +# xppref32.lib # zlib32.lib + +include <$(DEPTH)\config\rules.mak> + + +INSTALL = $(MAKE_INSTALL) + +objs: $(OBJS) + +$(PROGRAM):: + $(INSTALL) $(DIST)/bin/pr3240.dll ./$(OBJDIR) + +programs: $(PROGRAM) + +install:: $(TARGETS) + $(INSTALL) $(TARGETS) $(DIST)/bin + +# ALLXPSTR.obj XP_ALLOC.obj XP_HASH.obj XP_RGB.obj XP_WRAP.obj +# CXPRINT.obj XP_C.cl XP_LIST.obj XP_SEC.obj netscape.exp +# CXPRNDLG.obj XP_CNTXT.obj XP_MD5.obj XP_STR.obj xp.pch +# EXPORT.obj XP_CORE.obj XP_MESG.obj XP_THRMO.obj xppref32.dll +# XPASSERT.obj XP_ERROR.obj XP_RECT.obj XP_TIME.obj +# XPLOCALE.obj XP_FILE.obj XP_REG.obj XP_TRACE.obj + +symbols: + @echo "CSRCS = $(CSRCS)" + @echo "INCS = $(INCS)" + @echo "OBJS = $(OBJS)" + @echo "LIBRARY = $(LIBRARY)" + @echo "PROGRAM = $(PROGRAM)" + @echo "TARGETS = $(TARGETS)" + @echo "DIST = $(DIST)" + @echo "VERSION_NUMBER = $(VERSION_NUMBER)" + @echo "WINFE = $(WINFE)" + @echo "DBM_LIB = $(DBM_LIB)" + @echo "INSTALL = $(INSTALL)" + diff --git a/security/nss/cmd/makepqg/makepqg.c b/security/nss/cmd/makepqg/makepqg.c new file mode 100644 index 000000000..028ef7259 --- /dev/null +++ b/security/nss/cmd/makepqg/makepqg.c @@ -0,0 +1,290 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "prlong.h" + +#include "nss.h" +#include "secutil.h" +#include "secitem.h" +#include "pk11func.h" +#include "pk11pqg.h" +#include "pqgutil.h" +#include "secrng.h" + +#if defined(XP_UNIX) +#include <unistd.h> +#endif + +#include "plgetopt.h" + +#define BPB 8 /* bits per byte. */ + +char *progName; + + +const SEC_ASN1Template seckey_PQGParamsTemplate[] = { + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECKEYPQGParams) }, + { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,prime) }, + { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,subPrime) }, + { SEC_ASN1_INTEGER, offsetof(SECKEYPQGParams,base) }, + { 0, } +}; + + + +void +Usage(void) +{ + fprintf(stderr, "Usage: %s\n", progName); + fprintf(stderr, +"-a Output DER-encoded PQG params, BTOA encoded.\n" +" -l prime-length Length of prime in bits (1024 is default)\n" +" -o file Output to this file (default is stdout)\n" +"-b Output DER-encoded PQG params in binary\n" +" -l prime-length Length of prime in bits (1024 is default)\n" +" -o file Output to this file (default is stdout)\n" +"-r Output P, Q and G in ASCII hexadecimal. \n" +" -l prime-length Length of prime in bits (1024 is default)\n" +" -o file Output to this file (default is stdout)\n" +"-g bits Generate SEED this many bits long.\n" +); + exit(-1); + +} + +int +outputPQGParams(PQGParams * pqgParams, PRBool output_binary, PRBool output_raw, + FILE * outFile) +{ + PRArenaPool * arena = NULL; + char * PQG; + SECItem encodedParams; + + if (output_raw) { + SECItem item; + + PK11_PQG_GetPrimeFromParams(pqgParams, &item); + SECU_PrintInteger(outFile, &item, "Prime", 1); + SECITEM_FreeItem(&item, PR_FALSE); + + PK11_PQG_GetSubPrimeFromParams(pqgParams, &item); + SECU_PrintInteger(outFile, &item, "Subprime", 1); + SECITEM_FreeItem(&item, PR_FALSE); + + PK11_PQG_GetBaseFromParams(pqgParams, &item); + SECU_PrintInteger(outFile, &item, "Base", 1); + SECITEM_FreeItem(&item, PR_FALSE); + + fprintf(outFile, "\n"); + return 0; + } + + encodedParams.data = NULL; + encodedParams.len = 0; + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + SEC_ASN1EncodeItem(arena, &encodedParams, pqgParams, + seckey_PQGParamsTemplate); + if (output_binary) { + fwrite(encodedParams.data, encodedParams.len, sizeof(char), outFile); + printf("\n"); + return 0; + } + + /* must be output ASCII */ + PQG = BTOA_DataToAscii(encodedParams.data, encodedParams.len); + + fprintf(outFile,"%s",PQG); + printf("\n"); + return 0; +} + +int +outputPQGVerify(PQGVerify * pqgVerify, PRBool output_binary, PRBool output_raw, + FILE * outFile) +{ + if (output_raw) { + SECItem item; + unsigned int counter; + + PK11_PQG_GetHFromVerify(pqgVerify, &item); + SECU_PrintInteger(outFile, &item, "h", 1); + SECITEM_FreeItem(&item, PR_FALSE); + + PK11_PQG_GetSeedFromVerify(pqgVerify, &item); + SECU_PrintInteger(outFile, &item, "SEED", 1); + fprintf(outFile, " g: %d\n", item.len * BPB); + SECITEM_FreeItem(&item, PR_FALSE); + + counter = PK11_PQG_GetCounterFromVerify(pqgVerify); + fprintf(outFile, " counter: %d\n", counter); + fprintf(outFile, "\n"); + return 0; + } + return 0; +} + +int +main(int argc, char **argv) +{ + FILE * outFile = NULL; + PQGParams * pqgParams = NULL; + PQGVerify * pqgVerify = NULL; + int keySizeInBits = 1024; + int j; + int o; + int g = 0; + SECStatus rv = 0; + SECStatus passed = 0; + PRBool output_ascii = PR_FALSE; + PRBool output_binary = PR_FALSE; + PRBool output_raw = PR_FALSE; + PLOptState *optstate; + PLOptStatus status; + + + progName = strrchr(argv[0], '/'); + if (!progName) + progName = strrchr(argv[0], '\\'); + progName = progName ? progName+1 : argv[0]; + + /* Parse command line arguments */ + optstate = PL_CreateOptState(argc, argv, "l:abro:g:" ); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + + case 'l': + keySizeInBits = atoi(optstate->value); + break; + + case 'a': + output_ascii = PR_TRUE; + break; + + case 'b': + output_binary = PR_TRUE; + break; + + case 'r': + output_raw = PR_TRUE; + break; + + case 'o': + outFile = fopen(optstate->value, "wb"); + if (!outFile) { + fprintf(stderr, "%s: unable to open \"%s\" for writing\n", + progName, optstate->value); + rv = -1; + } + break; + + case 'g': + g = atoi(optstate->value); + break; + + default: + case '?': + Usage(); + break; + + } + } + + if (rv != 0) { + return rv; + } + + /* exactly 1 of these options must be set. */ + if (1 != ((output_ascii != PR_FALSE) + + (output_binary != PR_FALSE) + + (output_raw != PR_FALSE))) { + Usage(); + } + + j = PQG_PBITS_TO_INDEX(keySizeInBits); + if (j < 0) { + fprintf(stderr, "%s: Illegal prime length, \n" + "\tacceptable values are between 512 and 1024,\n" + "\tand divisible by 64\n", progName); + return -1; + } + if (g != 0 && (g < 160 || g >= 2048 || g % 8 != 0)) { + fprintf(stderr, "%s: Illegal g bits, \n" + "\tacceptable values are between 160 and 2040,\n" + "\tand divisible by 8\n", progName); + return -1; + } + + if (outFile == NULL) { + outFile = stdout; + } + + + NSS_NoDB_Init(NULL); + + if (g) + rv = PK11_PQG_ParamGenSeedLen((unsigned)j, (unsigned)(g/8), + &pqgParams, &pqgVerify); + else + rv = PK11_PQG_ParamGen((unsigned)j, &pqgParams, &pqgVerify); + + if (rv != SECSuccess || pqgParams == NULL) { + fprintf(stderr, "%s: PQG parameter generation failed.\n", progName); + goto loser; + } + fprintf(stderr, "%s: PQG parameter generation completed.\n", progName); + + o = outputPQGParams(pqgParams, output_binary, output_raw, outFile); + o = outputPQGVerify(pqgVerify, output_binary, output_raw, outFile); + + rv = PK11_PQG_VerifyParams(pqgParams, pqgVerify, &passed); + if (rv != SECSuccess) { + fprintf(stderr, "%s: PQG parameter verification aborted.\n", progName); + goto loser; + } + if (passed != SECSuccess) { + fprintf(stderr, "%s: PQG parameters failed verification.\n", progName); + goto loser; + } + fprintf(stderr, "%s: PQG parameters passed verification.\n", progName); + + PK11_PQG_DestroyParams(pqgParams); + PK11_PQG_DestroyVerify(pqgVerify); + return 0; + +loser: + PK11_PQG_DestroyParams(pqgParams); + PK11_PQG_DestroyVerify(pqgVerify); + return 1; +} diff --git a/security/nss/cmd/makepqg/manifest.mn b/security/nss/cmd/makepqg/manifest.mn new file mode 100644 index 000000000..328797094 --- /dev/null +++ b/security/nss/cmd/makepqg/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +# This next line is used by .mk files +# and gets translated into $LINCS in manifest.mnw +REQUIRES = nss seccmd dbm + +# DIRS = + +CSRCS = makepqg.c + +PROGRAM = makepqg + +#USE_STATIC_LIBS = 1 + diff --git a/security/nss/cmd/makepqg/testit.ksh b/security/nss/cmd/makepqg/testit.ksh new file mode 100644 index 000000000..98cb7fa9d --- /dev/null +++ b/security/nss/cmd/makepqg/testit.ksh @@ -0,0 +1,41 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +COUNTER=75 +while [ $COUNTER -ge "1" ] +do + COUNTER=$(eval expr $COUNTER - 1) + echo $COUNTER + */makepqg.exe -r -l 640 -g 160 || exit 1 +done + diff --git a/security/nss/cmd/manifest.mn b/security/nss/cmd/manifest.mn new file mode 100644 index 000000000..13289a7d3 --- /dev/null +++ b/security/nss/cmd/manifest.mn @@ -0,0 +1,90 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +DEPTH = ../.. +# MODULE = seccmd + +REQUIRES = nss nspr libdbm + +DIRS = lib \ + zlib \ + atob \ + bltest \ + btoa \ + certcgi \ + certutil \ + checkcert \ + crlutil \ + dbtest \ + derdump \ + digest \ + makepqg \ + ocspclnt \ + oidcalc \ + p7content \ + p7env \ + p7sign \ + p7verify \ + pk12util \ + pp \ + rngtest \ + rsaperf \ + sdrtest \ + selfserv \ + signtool \ + signver \ + shlibsign \ + smimetools \ + SSLsample \ + ssltap \ + strsclnt \ + swfort \ + tstclnt \ + vfyserv \ + modutil \ + $(NULL) + +TEMPORARILY_DONT_BUILD = \ + $(NULL) + +# rsaperf \ +# +# needs to look at what needs to happen to make jar build in +# the binary release environment. +# +# perror requires lib/strerror.c which requires the client code installed +# to build (requires allxpstr.h) +# +DONT_BULD = jar \ + perror \ +$(NULL) diff --git a/security/nss/cmd/modutil/Makefile b/security/nss/cmd/modutil/Makefile new file mode 100644 index 000000000..3d2bbb412 --- /dev/null +++ b/security/nss/cmd/modutil/Makefile @@ -0,0 +1,80 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + +# +# Cancel the built-in implicit yacc and lex rules. +# + +%.c: %.y +%.c: %.l diff --git a/security/nss/cmd/modutil/README b/security/nss/cmd/modutil/README new file mode 100644 index 000000000..12d192c9f --- /dev/null +++ b/security/nss/cmd/modutil/README @@ -0,0 +1,7 @@ + CRYPTOGRAPHIC MODULE UTILITY (modutil) + VERSION 1.0 + =============================================== + +The file specification.html documentats the software. + +The file pk11jar.html documents the PKCS #11 JAR format. diff --git a/security/nss/cmd/modutil/config.mk b/security/nss/cmd/modutil/config.mk new file mode 100644 index 000000000..9f0cdf1e4 --- /dev/null +++ b/security/nss/cmd/modutil/config.mk @@ -0,0 +1,77 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +####################################################################### +# Set the LDFLAGS value to encompass all normal link options, all # +# library names, and all special system linking options # +####################################################################### + +LDFLAGS = \ + $(DYNAMIC_LIB_PATH) \ + $(LDOPTS) \ + $(LIBSECTOOLS) \ + $(LIBSECMOD) \ + $(LIBHASH) \ + $(LIBCERT) \ + $(LIBKEY) \ + $(LIBCRYPTO) \ + $(LIBSECUTIL) \ + $(LIBDBM) \ + $(LIBPLC3) \ + $(LIBPLDS3) \ + $(LIBPR3) \ + $(DLLSYSTEM) \ + $(LIBJAR) \ + $(LIBZLIB) \ + $(LIBPKCS7) \ + $(LIBPLC3) + +# Strip out the symbols +ifdef BUILD_OPT + ifneq (,$(filter-out WIN%,$(OS_TARGET))) + LDFLAGS += -s + endif +endif + +####################################################################### +# Adjust specific variables for all platforms # +####################################################################### + + +ifeq (,$(filter-out WIN%,$(OS_TARGET))) + PACKAGE_FILES = license.txt README.TXT specification.html pk11jar.html modutil.exe +else + PACKAGE_FILES = license.doc README specification.html pk11jar.html modutil +endif + +ARCHIVE_NAME = modutil_$(OS_TARGET)$(OS_RELEASE) diff --git a/security/nss/cmd/modutil/error.h b/security/nss/cmd/modutil/error.h new file mode 100644 index 000000000..560e317db --- /dev/null +++ b/security/nss/cmd/modutil/error.h @@ -0,0 +1,182 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 MODUTIL_ERROR_H +#define MODUTIL_ERROR_H + +typedef enum { + NO_ERR=0, + INVALID_USAGE_ERR, + UNEXPECTED_ARG_ERR, + UNKNOWN_OPTION_ERR, + MULTIPLE_COMMAND_ERR, + OPTION_NEEDS_ARG_ERR, + DUPLICATE_OPTION_ERR, + MISSING_PARAM_ERR, + INVALID_FIPS_ARG, + NO_COMMAND_ERR, + NO_DBDIR_ERR, + FIPS_SWITCH_FAILED_ERR, + FIPS_ALREADY_ON_ERR, + FIPS_ALREADY_OFF_ERR, + FILE_ALREADY_EXISTS_ERR, + FILE_DOESNT_EXIST_ERR, + FILE_NOT_READABLE_ERR, + FILE_NOT_WRITEABLE_ERR, + DIR_DOESNT_EXIST_ERR, + DIR_NOT_READABLE_ERR, + DIR_NOT_WRITEABLE_ERR, + INVALID_CONSTANT_ERR, + ADD_MODULE_FAILED_ERR, + ADD_MODULE_FAILED_STATUS_ERR, + OUT_OF_MEM_ERR, + DELETE_INTERNAL_ERR, + DELETE_FAILED_ERR, + NO_LIST_LOCK_ERR, + NO_MODULE_LIST_ERR, + NO_SUCH_MODULE_ERR, + MOD_INFO_ERR, + SLOT_INFO_ERR, + TOKEN_INFO_ERR, + NO_SUCH_TOKEN_ERR, + CHANGEPW_FAILED_ERR, + BAD_PW_ERR, + DB_ACCESS_ERR, + AUTHENTICATION_FAILED_ERR, + NO_SUCH_SLOT_ERR, + ENABLE_FAILED_ERR, + UPDATE_MOD_FAILED_ERR, + DEFAULT_FAILED_ERR, + UNDEFAULT_FAILED_ERR, + STDIN_READ_ERR, + UNSPECIFIED_ERR, + NOCERTDB_MISUSE_ERR, + NSS_INITIALIZE_FAILED_ERR, + + LAST_ERR /* must be last */ +} Error; +#define SUCCESS NO_ERR + +/* !!! Should move this into its own .c and un-static it. */ +static char *errStrings[] = { + "Operation completed successfully.\n", + "ERROR: Invalid command line.\n", + "ERROR: Not expecting argument \"%s\".\n", + "ERROR: Unknown option: %s.\n", + "ERROR: %s: multiple commands are not allowed on the command line.\n", + "ERROR: %s: option needs an argument.\n", + "ERROR: %s: option cannot be given more than once.\n", + "ERROR: Command \"%s\" requires parameter \"%s\".\n", + "ERROR: Argument to -fips must be \"true\" or \"false\".\n", + "ERROR: No command was specified.\n", + "ERROR: Cannot determine database directory: use the -dbdir option.\n", + "ERROR: Unable to switch FIPS modes.\n", + "FIPS mode already enabled.\n", + "FIPS mode already disabled.\n", + "ERROR: File \"%s\" already exists.\n", + "ERROR: File \"%s\" does not exist.\n", + "ERROR: File \"%s\" is not readable.\n", + "ERROR: File \"%s\" is not writeable.\n", + "ERROR: Directory \"%s\" does not exist.\n", + "ERROR: Directory \"%s\" is not readable.\n", + "ERROR: Directory \"%s\" is not writeable.\n", + "\"%s\" is not a recognized value.\n", + "ERROR: Failed to add module \"%s\".\n", + "ERROR: Failed to add module \"%s\". Probable cause : \"%s\".\n", + "ERROR: Out of memory.\n", + "ERROR: Cannot delete internal module.\n", + "ERROR: Failed to delete module \"%s\".\n", + "ERROR: Unable to obtain lock on module list.\n", + "ERROR: Unable to obtain module list.\n", + "ERROR: Module \"%s\" not found in database.\n", + "ERROR: Unable to get information about module \"%s\".\n", + "ERROR: Unable to get information about slot \"%s\".\n", + "ERROR: Unable to get information about token \"%s\".\n", + "ERROR: Token \"%s\" not found.\n", + "ERROR: Unable to change password on token \"%s\".\n", + "ERROR: Incorrect password.\n", + "ERROR: Unable to access database \"%s\".\n", + "ERROR: Unable to authenticate to token \"%s\".\n", + "ERROR: Slot \"%s\" not found.\n", + "ERROR: Failed to %s slot \"%s\".\n", + "ERROR: Failed to update module \"%s\".\n", + "ERROR: Failed to change defaults.\n", + "ERROR: Failed to change default.\n", + "ERROR: Unable to read from standard input.\n", + "ERROR: Unknown error occurred.\n", + "ERROR: -nocertdb option can only be used with the -jar command.\n" + "ERROR: NSS_Initialize() failed.\n" +}; + +typedef enum { + FIPS_ENABLED_MSG=0, + FIPS_DISABLED_MSG, + USING_DBDIR_MSG, + CREATING_DB_MSG, + ADD_MODULE_SUCCESS_MSG, + DELETE_SUCCESS_MSG, + CHANGEPW_SUCCESS_MSG, + BAD_PW_MSG, + PW_MATCH_MSG, + DONE_MSG, + ENABLE_SUCCESS_MSG, + DEFAULT_SUCCESS_MSG, + UNDEFAULT_SUCCESS_MSG, + BROWSER_RUNNING_MSG, + ABORTING_MSG, + + LAST_MSG /* must be last */ +} Message; + +static char *msgStrings[] = { + "FIPS mode enabled.\n", + "FIPS mode disabled.\n", + "Using database directory %s...\n", + "Creating \"%s\"...", + "Module \"%s\" added to database.\n", + "Module \"%s\" deleted from database.\n", + "Token \"%s\" password changed successfully.\n", + "Incorrect password, try again...\n", + "Passwords do not match, try again...\n", + "done.\n", + "Slot \"%s\" %s.\n", + "Successfully changed defaults.\n", + "Successfully changed defaults.\n", +"\nWARNING: Performing this operation while the browser is running could cause" +"\ncorruption of your security databases. If the browser is currently running," +"\nyou should exit browser before continuing this operation. Type " +"\n'q <enter>' to abort, or <enter> to continue: ", + "\nAborting...\n" +}; + +#endif /* MODUTIL_ERROR_H */ diff --git a/security/nss/cmd/modutil/install-ds.c b/security/nss/cmd/modutil/install-ds.c new file mode 100644 index 000000000..e6b90ded3 --- /dev/null +++ b/security/nss/cmd/modutil/install-ds.c @@ -0,0 +1,1541 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "install-ds.h" +#include <prmem.h> +#include <plstr.h> +#include <prprf.h> +#include <string.h> + +#define PORT_Strcasecmp PL_strcasecmp + +#define MODULE_FILE_STRING "ModuleFile" +#define MODULE_NAME_STRING "ModuleName" +#define MECH_FLAGS_STRING "DefaultMechanismFlags" +#define CIPHER_FLAGS_STRING "DefaultCipherFlags" +#define FILES_STRING "Files" +#define FORWARD_COMPATIBLE_STRING "ForwardCompatible" +#define PLATFORMS_STRING "Platforms" +#define RELATIVE_DIR_STRING "RelativePath" +#define ABSOLUTE_DIR_STRING "AbsolutePath" +#define FILE_PERMISSIONS_STRING "FilePermissions" +#define EQUIVALENT_PLATFORM_STRING "EquivalentPlatform" +#define EXECUTABLE_STRING "Executable" + +#define DEFAULT_PERMISSIONS 0777 + +#define PLATFORM_SEPARATOR_CHAR ':' + +/* Error codes */ +enum { + BOGUS_RELATIVE_DIR=0, + BOGUS_ABSOLUTE_DIR, + BOGUS_FILE_PERMISSIONS, + NO_RELATIVE_DIR, + NO_ABSOLUTE_DIR, + EMPTY_PLATFORM_STRING, + BOGUS_PLATFORM_STRING, + REPEAT_MODULE_FILE, + REPEAT_MODULE_NAME, + BOGUS_MODULE_FILE, + BOGUS_MODULE_NAME, + REPEAT_MECH, + BOGUS_MECH_FLAGS, + REPEAT_CIPHER, + BOGUS_CIPHER_FLAGS, + REPEAT_FILES, + REPEAT_EQUIV, + BOGUS_EQUIV, + EQUIV_TOO_MUCH_INFO, + NO_FILES, + NO_MODULE_FILE, + NO_MODULE_NAME, + NO_PLATFORMS, + EQUIV_LOOP, + UNKNOWN_MODULE_FILE +}; + +/* Indexed by the above error codes */ +static const char *errString[] = { + "%s: Invalid relative directory", + "%s: Invalid absolute directory", + "%s: Invalid file permissions", + "%s: No relative directory specified", + "%s: No absolute directory specified", + "Empty string given for platform name", + "%s: invalid platform string", + "More than one ModuleFile entry given for platform %s", + "More than one ModuleName entry given for platform %s", + "Invalid ModuleFile specification for platform %s", + "Invalid ModuleName specification for platform %s", + "More than one DefaultMechanismFlags entry given for platform %s", + "Invalid DefaultMechanismFlags specification for platform %s", + "More than one DefaultCipherFlags entry given for platform %s", + "Invalid DefaultCipherFlags entry given for platform %s", + "More than one Files entry given for platform %s", + "More than one EquivalentPlatform entry given for platform %s", + "Invalid EquivalentPlatform specification for platform %s", + "Module %s uses an EquivalentPlatform but also specifies its own" + " information", + "No Files specification in module %s", + "No ModuleFile specification in module %s", + "No ModuleName specification in module %s", + "No Platforms specification in installer script", + "Platform %s has an equivalency loop", + "Module file \"%s\" in platform \"%s\" does not exist" +}; + +static char* PR_Strdup(const char* str); + +#define PAD(x) {int i; for(i=0;i<x;i++) printf(" ");} +#define PADINC 4 + +Pk11Install_File* +Pk11Install_File_new() +{ + Pk11Install_File* new_this; + new_this = (Pk11Install_File*)PR_Malloc(sizeof(Pk11Install_File)); + Pk11Install_File_init(new_this); + return new_this; +} + +void +Pk11Install_File_init(Pk11Install_File* _this) +{ + _this->jarPath=NULL; + _this->relativePath=NULL; + _this->absolutePath=NULL; + _this->executable=PR_FALSE; + _this->permissions=0; +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: ~Pk11Install_File +// Class: Pk11Install_File +// Notes: Destructor. +*/ +void +Pk11Install_File_delete(Pk11Install_File* _this) +{ + Pk11Install_File_Cleanup(_this); +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: Cleanup +// Class: Pk11Install_File +*/ +void +Pk11Install_File_Cleanup(Pk11Install_File* _this) +{ + if(_this->jarPath) { + PR_Free(_this->jarPath); + _this->jarPath = NULL; + } + if(_this->relativePath) { + PR_Free(_this->relativePath); + _this->relativePath = NULL; + } + if(_this->absolutePath) { + PR_Free(_this->absolutePath); + _this->absolutePath = NULL; + } + + _this->permissions = 0; + _this->executable = PR_FALSE; +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: Generate +// Class: Pk11Install_File +// Notes: Creates a file data structure from a syntax tree. +// Returns: NULL for success, otherwise an error message. +*/ +char* +Pk11Install_File_Generate(Pk11Install_File* _this, + const Pk11Install_Pair *pair) +{ + Pk11Install_ListIter *iter; + Pk11Install_Value *val; + Pk11Install_Pair *subpair; + Pk11Install_ListIter *subiter; + Pk11Install_Value *subval; + char* errStr; + char *endp; + PRBool gotPerms; + + iter=NULL; + subiter=NULL; + errStr=NULL; + gotPerms=PR_FALSE; + + /* Clear out old values */ + Pk11Install_File_Cleanup(_this); + + _this->jarPath = PR_Strdup(pair->key); + + /* Go through all the pairs under this file heading */ + iter = Pk11Install_ListIter_new(pair->list); + for( ; (val = iter->current); Pk11Install_ListIter_nextItem(iter)) { + if(val->type == PAIR_VALUE) { + subpair = val->pair; + + /* Relative directory */ + if(!PORT_Strcasecmp(subpair->key, RELATIVE_DIR_STRING)) { + subiter = Pk11Install_ListIter_new(subpair->list); + subval = subiter->current; + if(!subval || (subval->type != STRING_VALUE)){ + errStr = PR_smprintf(errString[BOGUS_RELATIVE_DIR], + _this->jarPath); + goto loser; + } + _this->relativePath = PR_Strdup(subval->string); + Pk11Install_ListIter_delete(subiter); + subiter = NULL; + + /* Absolute directory */ + } else if( !PORT_Strcasecmp(subpair->key, ABSOLUTE_DIR_STRING)) { + subiter = Pk11Install_ListIter_new(subpair->list); + subval = subiter->current; + if(!subval || (subval->type != STRING_VALUE)){ + errStr = PR_smprintf(errString[BOGUS_ABSOLUTE_DIR], + _this->jarPath); + goto loser; + } + _this->absolutePath = PR_Strdup(subval->string); + Pk11Install_ListIter_delete(subiter); + subiter = NULL; + + /* file permissions */ + } else if( !PORT_Strcasecmp(subpair->key, + FILE_PERMISSIONS_STRING)) { + subiter = Pk11Install_ListIter_new(subpair->list); + subval = subiter->current; + if(!subval || (subval->type != STRING_VALUE)){ + errStr = PR_smprintf(errString[BOGUS_FILE_PERMISSIONS], + _this->jarPath); + goto loser; + } + _this->permissions = (int) strtol(subval->string, &endp, 8); + if(*endp != '\0' || subval->string == "\0") { + errStr = PR_smprintf(errString[BOGUS_FILE_PERMISSIONS], + _this->jarPath); + goto loser; + } + gotPerms = PR_TRUE; + Pk11Install_ListIter_delete(subiter); + subiter = NULL; + } + } else { + if(!PORT_Strcasecmp(val->string, EXECUTABLE_STRING)) { + _this->executable = PR_TRUE; + } + } + } + + /* Default permission value */ + if(!gotPerms) { + _this->permissions = DEFAULT_PERMISSIONS; + } + + /* Make sure we got all the information */ + if(!_this->relativePath && !_this->absolutePath) { + errStr = PR_smprintf(errString[NO_ABSOLUTE_DIR], _this->jarPath); + goto loser; + } +#if 0 + if(!_this->relativePath ) { + errStr = PR_smprintf(errString[NO_RELATIVE_DIR], _this->jarPath); + goto loser; + } + if(!_this->absolutePath) { + errStr = PR_smprintf(errString[NO_ABSOLUTE_DIR], _this->jarPath); + goto loser; + } +#endif + +loser: + if(iter) { + Pk11Install_ListIter_delete(iter); + PR_Free(iter); + } + if(subiter) { + Pk11Install_ListIter_delete(subiter); + PR_Free(subiter); + } + return errStr; +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: Print +// Class: Pk11Install_File +*/ +void +Pk11Install_File_Print(Pk11Install_File* _this, int pad) +{ + PAD(pad); printf("jarPath: %s\n", + _this->jarPath ? _this->jarPath : "<NULL>"); + PAD(pad); printf("relativePath: %s\n", + _this->relativePath ? _this->relativePath: "<NULL>"); + PAD(pad); printf("absolutePath: %s\n", + _this->absolutePath ? _this->absolutePath: "<NULL>"); + PAD(pad); printf("permissions: %o\n", _this->permissions); +} + +Pk11Install_PlatformName* +Pk11Install_PlatformName_new() +{ + Pk11Install_PlatformName* new_this; + new_this = (Pk11Install_PlatformName*) + PR_Malloc(sizeof(Pk11Install_PlatformName)); + Pk11Install_PlatformName_init(new_this); + return new_this; +} + +void +Pk11Install_PlatformName_init(Pk11Install_PlatformName* _this) +{ + _this->OS = NULL; + _this->verString = NULL; + _this->numDigits = 0; + _this->arch = NULL; +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: ~Pk11Install_PlatformName +// Class: Pk11Install_PlatformName +*/ +void +Pk11Install_PlatformName_delete(Pk11Install_PlatformName* _this) +{ + Pk11Install_PlatformName_Cleanup(_this); +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: Cleanup +// Class: Pk11Install_PlatformName +*/ +void +Pk11Install_PlatformName_Cleanup(Pk11Install_PlatformName* _this) +{ + if(_this->OS) { + PR_Free(_this->OS); + _this->OS = NULL; + } + if(_this->verString) { + int i; + for (i=0; i<_this->numDigits; i++) { + PR_Free(_this->verString[i]); + } + PR_Free(_this->verString); + _this->verString = NULL; + } + if(_this->arch) { + PR_Free(_this->arch); + _this->arch = NULL; + } + _this->numDigits = 0; +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: Generate +// Class: Pk11Install_PlatformName +// Notes: Extracts the information from a platform string. +*/ +char* +Pk11Install_PlatformName_Generate(Pk11Install_PlatformName* _this, + const char *str) +{ + char *errStr; + char *copy; + char *end, *start; /* start and end of a section (OS, version, arch)*/ + char *pend, *pstart; /* start and end of one portion of version*/ + char *endp; /* used by strtol*/ + int periods, i; + + errStr=NULL; + copy=NULL; + + if(!str) { + errStr = PR_smprintf(errString[EMPTY_PLATFORM_STRING]); + goto loser; + } + copy = PR_Strdup(str); + + /* + // Get the OS + */ + end = strchr(copy, PLATFORM_SEPARATOR_CHAR); + if(!end || end==copy) { + errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str); + goto loser; + } + *end = '\0'; + + _this->OS = PR_Strdup(copy); + + /* + // Get the digits of the version of form: x.x.x (arbitrary number of digits) + */ + + start = end+1; + end = strchr(start, PLATFORM_SEPARATOR_CHAR); + if(!end) { + errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str); + goto loser; + } + *end = '\0'; + + if(end!=start) { + /* Find out how many periods*/ + periods = 0; + pstart = start; + while( (pend=strchr(pstart, '.')) ) { + periods++; + pstart = pend+1; + } + _this->numDigits= 1+ periods; + _this->verString = (char**)PR_Malloc(sizeof(char*)*_this->numDigits); + + pstart = start; + i = 0; + /* Get the digits before each period*/ + while( (pend=strchr(pstart, '.')) ) { + if(pend == pstart) { + errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str); + goto loser; + } + *pend = '\0'; + _this->verString[i] = PR_Strdup(pstart); + endp = pend; + if(endp==pstart || (*endp != '\0')) { + errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str); + goto loser; + } + pstart = pend+1; + i++; + } + /* Last digit comes after the last period*/ + if(*pstart == '\0') { + errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str); + goto loser; + } + _this->verString[i] = PR_Strdup(pstart); + /* + if(endp==pstart || (*endp != '\0')) { + errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str); + goto loser; + } + */ + } else { + _this->verString = NULL; + _this->numDigits = 0; + } + + /* + // Get the architecture + */ + start = end+1; + if( strchr(start, PLATFORM_SEPARATOR_CHAR) ) { + errStr = PR_smprintf(errString[BOGUS_PLATFORM_STRING], str); + goto loser; + } + _this->arch = PR_Strdup(start); + + if(copy) { + PR_Free(copy); + } + return NULL; +loser: + if(_this->OS) { + PR_Free(_this->OS); + _this->OS = NULL; + } + if(_this->verString) { + for (i=0; i<_this->numDigits; i++) { + PR_Free(_this->verString[i]); + } + PR_Free(_this->verString); + _this->verString = NULL; + } + _this->numDigits = 0; + if(_this->arch) { + PR_Free(_this->arch); + _this->arch = NULL; + } + + return errStr; +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: operator == +// Class: Pk11Install_PlatformName +// Returns: PR_TRUE if the platform have the same OS, arch, and version +*/ +PRBool +Pk11Install_PlatformName_equal(Pk11Install_PlatformName* _this, + Pk11Install_PlatformName* cmp) +{ + int i; + + if(!_this->OS || !_this->arch || !cmp->OS || !cmp->arch) { + return PR_FALSE; + } + + if( PORT_Strcasecmp(_this->OS, cmp->OS) || + PORT_Strcasecmp(_this->arch, cmp->arch) || + _this->numDigits != cmp->numDigits ) { + return PR_FALSE; + } + + for(i=0; i < _this->numDigits; i++) { + if(PORT_Strcasecmp(_this->verString[i], cmp->verString[i])) { + return PR_FALSE; + } + } + return PR_TRUE; +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: operator <= +// Class: Pk11Install_PlatformName +// Returns: PR_TRUE if the platform have the same OS and arch and a lower +// or equal release. +*/ +PRBool +Pk11Install_PlatformName_lteq(Pk11Install_PlatformName* _this, + Pk11Install_PlatformName* cmp) +{ + return (Pk11Install_PlatformName_equal(_this,cmp) || + Pk11Install_PlatformName_lt(_this,cmp)) ? PR_TRUE : PR_FALSE; +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: operator < +// Class: Pk11Install_PlatformName +// Returns: PR_TRUE if the platform have the same OS and arch and a greater +// release. +*/ +PRBool +Pk11Install_PlatformName_lt(Pk11Install_PlatformName* _this, + Pk11Install_PlatformName* cmp) +{ + int i, scmp; + + if(!_this->OS || !_this->arch || !cmp->OS || !cmp->arch) { + return PR_FALSE; + } + + if( PORT_Strcasecmp(_this->OS, cmp->OS) ) { + return PR_FALSE; + } + if( PORT_Strcasecmp(_this->arch, cmp->arch) ) { + return PR_FALSE; + } + + for(i=0; (i < _this->numDigits) && (i < cmp->numDigits); i++) { + scmp = PORT_Strcasecmp(_this->verString[i], cmp->verString[i]); + if (scmp > 0) { + return PR_FALSE; + } else if (scmp < 0) { + return PR_TRUE; + } + } + /* All the digits they have in common are the same. */ + if(_this->numDigits < cmp->numDigits) { + return PR_TRUE; + } + + return PR_FALSE; +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: GetString +// Class: Pk11Install_PlatformName +// Returns: String composed of OS, release, and architecture separated +// by the separator char. Memory is allocated by this function +// but is the responsibility of the caller to de-allocate. +*/ +char* +Pk11Install_PlatformName_GetString(Pk11Install_PlatformName* _this) +{ + char *ret; + char *ver; + char *OS_; + char *arch_; + + OS_=NULL; + arch_=NULL; + + OS_ = _this->OS ? _this->OS : ""; + arch_ = _this->arch ? _this->arch : ""; + + ver = Pk11Install_PlatformName_GetVerString(_this); + ret = PR_smprintf("%s%c%s%c%s", OS_, PLATFORM_SEPARATOR_CHAR, ver, + PLATFORM_SEPARATOR_CHAR, arch_); + + PR_Free(ver); + + return ret; +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: GetVerString +// Class: Pk11Install_PlatformName +// Returns: The version string for this platform, in the form x.x.x with an +// arbitrary number of digits. Memory allocated by function, +// must be de-allocated by caller. +*/ +char* +Pk11Install_PlatformName_GetVerString(Pk11Install_PlatformName* _this) +{ + char *tmp; + char *ret; + int i; + char buf[80]; + + tmp = (char*)PR_Malloc(80*_this->numDigits+1); + tmp[0] = '\0'; + + for(i=0; i < _this->numDigits-1; i++) { + sprintf(buf, "%s.", _this->verString[i]); + strcat(tmp, buf); + } + if(i < _this->numDigits) { + sprintf(buf, "%s", _this->verString[i]); + strcat(tmp, buf); + } + + ret = PR_Strdup(tmp); + free(tmp); + + return ret; +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: Print +// Class: Pk11Install_PlatformName +*/ +void +Pk11Install_PlatformName_Print(Pk11Install_PlatformName* _this, int pad) +{ + PAD(pad); printf("OS: %s\n", _this->OS ? _this->OS : "<NULL>"); + PAD(pad); printf("Digits: "); + if(_this->numDigits == 0) { + printf("None\n"); + } else { + printf("%s\n", Pk11Install_PlatformName_GetVerString(_this)); + } + PAD(pad); printf("arch: %s\n", _this->arch ? _this->arch : "<NULL>"); +} + +Pk11Install_Platform* +Pk11Install_Platform_new() +{ + Pk11Install_Platform* new_this; + new_this = (Pk11Install_Platform*)PR_Malloc(sizeof(Pk11Install_Platform)); + Pk11Install_Platform_init(new_this); + return new_this; +} + +void +Pk11Install_Platform_init(Pk11Install_Platform* _this) +{ + Pk11Install_PlatformName_init(&_this->name); + Pk11Install_PlatformName_init(&_this->equivName); + _this->equiv = NULL; + _this->usesEquiv = PR_FALSE; + _this->moduleFile = NULL; + _this->moduleName = NULL; + _this->modFile = -1; + _this->mechFlags = 0; + _this->cipherFlags = 0; + _this->files = NULL; + _this->numFiles = 0; +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: ~Pk11Install_Platform +// Class: Pk11Install_Platform +*/ +void +Pk11Install_Platform_delete(Pk11Install_Platform* _this) +{ + Pk11Install_Platform_Cleanup(_this); +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: Cleanup +// Class: Pk11Install_Platform +*/ +void +Pk11Install_Platform_Cleanup(Pk11Install_Platform* _this) +{ + int i; + if(_this->moduleFile) { + PR_Free(_this->moduleFile); + _this->moduleFile = NULL; + } + if(_this->moduleName) { + PR_Free(_this->moduleName); + _this->moduleName = NULL; + } + if(_this->files) { + for (i=0;i<_this->numFiles;i++) { + Pk11Install_File_delete(&_this->files[i]); + } + PR_Free(_this->files); + _this->files = NULL; + } + _this->equiv = NULL; + _this->usesEquiv = PR_FALSE; + _this->modFile = -1; + _this->numFiles = 0; + _this->mechFlags = _this->cipherFlags = 0; +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: Generate +// Class: Pk11Install_Platform +// Notes: Creates a platform data structure from a syntax tree. +// Returns: NULL for success, otherwise an error message. +*/ +char* +Pk11Install_Platform_Generate(Pk11Install_Platform* _this, + const Pk11Install_Pair *pair) +{ + char* errStr; + char* endptr; + char* tmp; + int i; + Pk11Install_ListIter *iter; + Pk11Install_Value *val; + Pk11Install_Value *subval; + Pk11Install_Pair *subpair; + Pk11Install_ListIter *subiter; + PRBool gotModuleFile, gotModuleName, gotMech, + gotCipher, gotFiles, gotEquiv; + + errStr=NULL; + iter=subiter=NULL; + val=subval=NULL; + subpair=NULL; + gotModuleFile=gotModuleName=gotMech=gotCipher=gotFiles=gotEquiv=PR_FALSE; + Pk11Install_Platform_Cleanup(_this); + + errStr = Pk11Install_PlatformName_Generate(&_this->name,pair->key); + if(errStr) { + tmp = PR_smprintf("%s: %s", pair->key, errStr); + PR_smprintf_free(errStr); + errStr = tmp; + goto loser; + } + + iter = Pk11Install_ListIter_new(pair->list); + for( ; (val=iter->current); Pk11Install_ListIter_nextItem(iter)) { + if(val->type==PAIR_VALUE) { + subpair = val->pair; + + if( !PORT_Strcasecmp(subpair->key, MODULE_FILE_STRING)) { + if(gotModuleFile) { + errStr = PR_smprintf(errString[REPEAT_MODULE_FILE], + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + subiter = Pk11Install_ListIter_new(subpair->list); + subval = subiter->current; + if(!subval || (subval->type != STRING_VALUE)) { + errStr = PR_smprintf(errString[BOGUS_MODULE_FILE], + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + _this->moduleFile = PR_Strdup(subval->string); + Pk11Install_ListIter_delete(subiter); + PR_Free(subiter); + subiter = NULL; + gotModuleFile = PR_TRUE; + } else if(!PORT_Strcasecmp(subpair->key, MODULE_NAME_STRING)){ + if(gotModuleName) { + errStr = PR_smprintf(errString[REPEAT_MODULE_NAME], + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + subiter = Pk11Install_ListIter_new(subpair->list); + subval = subiter->current; + if(!subval || (subval->type != STRING_VALUE)) { + errStr = PR_smprintf(errString[BOGUS_MODULE_NAME], + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + _this->moduleName = PR_Strdup(subval->string); + Pk11Install_ListIter_delete(subiter); + PR_Free(subiter); + subiter = NULL; + gotModuleName = PR_TRUE; + } else if(!PORT_Strcasecmp(subpair->key, MECH_FLAGS_STRING)) { + endptr=NULL; + + if(gotMech) { + errStr = PR_smprintf(errString[REPEAT_MECH], + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + subiter = Pk11Install_ListIter_new(subpair->list); + subval = subiter->current; + if(!subval || (subval->type != STRING_VALUE)) { + errStr = PR_smprintf(errString[BOGUS_MECH_FLAGS], + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + _this->mechFlags = strtol(subval->string, &endptr, 0); + if(*endptr!='\0' || (endptr==subval->string) ) { + errStr = PR_smprintf(errString[BOGUS_MECH_FLAGS], + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + Pk11Install_ListIter_delete(subiter); + PR_Free(subiter); + subiter=NULL; + gotMech = PR_TRUE; + } else if(!PORT_Strcasecmp(subpair->key,CIPHER_FLAGS_STRING)) { + endptr=NULL; + + if(gotCipher) { + errStr = PR_smprintf(errString[REPEAT_CIPHER], + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + subiter = Pk11Install_ListIter_new(subpair->list); + subval = subiter->current; + if(!subval || (subval->type != STRING_VALUE)) { + errStr = PR_smprintf(errString[BOGUS_CIPHER_FLAGS], + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + _this->cipherFlags = strtol(subval->string, &endptr, 0); + if(*endptr!='\0' || (endptr==subval->string) ) { + errStr = PR_smprintf(errString[BOGUS_CIPHER_FLAGS], + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + Pk11Install_ListIter_delete(subiter); + PR_Free(subiter); + subiter=NULL; + gotCipher = PR_TRUE; + } else if(!PORT_Strcasecmp(subpair->key, FILES_STRING)) { + if(gotFiles) { + errStr = PR_smprintf(errString[REPEAT_FILES], + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + subiter = Pk11Install_ListIter_new(subpair->list); + _this->numFiles = subpair->list->numPairs; + _this->files = (Pk11Install_File*) + PR_Malloc(sizeof(Pk11Install_File)*_this->numFiles); + for(i=0; i < _this->numFiles; i++, + Pk11Install_ListIter_nextItem(subiter)) { + Pk11Install_File_init(&_this->files[i]); + val = subiter->current; + if(val && (val->type==PAIR_VALUE)) { + errStr = Pk11Install_File_Generate(&_this->files[i],val->pair); + if(errStr) { + tmp = PR_smprintf("%s: %s", + Pk11Install_PlatformName_GetString(&_this->name),errStr); + PR_smprintf_free(errStr); + errStr = tmp; + goto loser; + } + } + } + gotFiles = PR_TRUE; + } else if(!PORT_Strcasecmp(subpair->key, + EQUIVALENT_PLATFORM_STRING)) { + if(gotEquiv) { + errStr = PR_smprintf(errString[REPEAT_EQUIV], + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + subiter = Pk11Install_ListIter_new(subpair->list); + subval = subiter->current; + if(!subval || (subval->type != STRING_VALUE) ) { + errStr = PR_smprintf(errString[BOGUS_EQUIV], + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + errStr = Pk11Install_PlatformName_Generate(&_this->equivName, + subval->string); + if(errStr) { + tmp = PR_smprintf("%s: %s", + Pk11Install_PlatformName_GetString(&_this->name), errStr); + tmp = PR_smprintf("%s: %s", + Pk11Install_PlatformName_GetString(&_this->name), errStr); + PR_smprintf_free(errStr); + errStr = tmp; + goto loser; + } + _this->usesEquiv = PR_TRUE; + } + } + } + + /* Make sure we either have an EquivalentPlatform or all the other info */ + if(_this->usesEquiv && + (gotFiles || gotModuleFile || gotModuleName || gotMech || gotCipher)) { + errStr = PR_smprintf(errString[EQUIV_TOO_MUCH_INFO], + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + if(!gotFiles && !_this->usesEquiv) { + errStr = PR_smprintf(errString[NO_FILES], + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + if(!gotModuleFile && !_this->usesEquiv) { + errStr= PR_smprintf(errString[NO_MODULE_FILE], + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + if(!gotModuleName && !_this->usesEquiv) { + errStr = PR_smprintf(errString[NO_MODULE_NAME], + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + + /* Point the modFile pointer to the correct file */ + if(gotModuleFile) { + for(i=0; i < _this->numFiles; i++) { + if(!PORT_Strcasecmp(_this->moduleFile, _this->files[i].jarPath) ) { + _this->modFile = i; + break; + } + } + if(_this->modFile==-1) { + errStr = PR_smprintf(errString[UNKNOWN_MODULE_FILE], + _this->moduleFile, + Pk11Install_PlatformName_GetString(&_this->name)); + goto loser; + } + } + +loser: + if(iter) { + PR_Free(iter); + } + if(subiter) { + PR_Free(subiter); + } + return errStr; +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: Print +// Class: Pk11Install_Platform +*/ +void +Pk11Install_Platform_Print(Pk11Install_Platform* _this, int pad) +{ + int i; + + PAD(pad); printf("Name:\n"); + Pk11Install_PlatformName_Print(&_this->name,pad+PADINC); + PAD(pad); printf("equivName:\n"); + Pk11Install_PlatformName_Print(&_this->equivName,pad+PADINC); + PAD(pad); + if(_this->usesEquiv) { + printf("Uses equiv, which points to:\n"); + Pk11Install_Platform_Print(_this->equiv,pad+PADINC); + } else { + printf("Doesn't use equiv\n"); + } + PAD(pad); + printf("Module File: %s\n", _this->moduleFile ? _this->moduleFile + : "<NULL>"); + PAD(pad); printf("mechFlags: %lx\n", _this->mechFlags); + PAD(pad); printf("cipherFlags: %lx\n", _this->cipherFlags); + PAD(pad); printf("Files:\n"); + for(i=0; i < _this->numFiles; i++) { + Pk11Install_File_Print(&_this->files[i],pad+PADINC); + PAD(pad); printf("--------------------\n"); + } +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: Pk11Install_Info +// Class: Pk11Install_Info +*/ +Pk11Install_Info* +Pk11Install_Info_new() +{ + Pk11Install_Info* new_this; + new_this = (Pk11Install_Info*)PR_Malloc(sizeof(Pk11Install_Info)); + Pk11Install_Info_init(new_this); + return new_this; +} + +void +Pk11Install_Info_init(Pk11Install_Info* _this) +{ + _this->platforms = NULL; + _this->numPlatforms = 0; + _this->forwardCompatible = NULL; + _this->numForwardCompatible = 0; +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: ~Pk11Install_Info +// Class: Pk11Install_Info +*/ +void +Pk11Install_Info_delete(Pk11Install_Info* _this) +{ + Pk11Install_Info_Cleanup(_this); +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: Cleanup +// Class: Pk11Install_Info +*/ +void +Pk11Install_Info_Cleanup(Pk11Install_Info* _this) +{ + int i; + if(_this->platforms) { + for (i=0;i<_this->numPlatforms;i++) { + Pk11Install_Platform_delete(&_this->platforms[i]); + } + PR_Free(&_this->platforms); + _this->platforms = NULL; + _this->numPlatforms = 0; + } + + if(_this->forwardCompatible) { + for (i=0;i<_this->numForwardCompatible;i++) { + Pk11Install_PlatformName_delete(&_this->forwardCompatible[i]); + } + PR_Free(&_this->forwardCompatible); + _this->numForwardCompatible = 0; + } +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: Generate +// Class: Pk11Install_Info +// Takes: Pk11Install_ValueList *list, the top-level list +// resulting from parsing an installer file. +// Returns: char*, NULL if successful, otherwise an error string. +// Caller is responsible for freeing memory. +*/ +char* +Pk11Install_Info_Generate(Pk11Install_Info* _this, + const Pk11Install_ValueList *list) +{ + char *errStr; + Pk11Install_ListIter *iter; + Pk11Install_Value *val; + Pk11Install_Pair *pair; + Pk11Install_ListIter *subiter; + Pk11Install_Value *subval; + Pk11Install_Platform *first, *second; + int i, j; + + errStr=NULL; + iter=subiter=NULL; + Pk11Install_Info_Cleanup(_this); + + iter = Pk11Install_ListIter_new(list); + for( ; (val=iter->current); Pk11Install_ListIter_nextItem(iter)) { + if(val->type == PAIR_VALUE) { + pair = val->pair; + + if(!PORT_Strcasecmp(pair->key, FORWARD_COMPATIBLE_STRING)) { + subiter = Pk11Install_ListIter_new(pair->list); + _this->numForwardCompatible = pair->list->numStrings; + _this->forwardCompatible = (Pk11Install_PlatformName*) + PR_Malloc(sizeof(Pk11Install_PlatformName)* + _this->numForwardCompatible); + for(i=0; i < _this->numForwardCompatible; i++, + Pk11Install_ListIter_nextItem(subiter)) { + subval = subiter->current; + if(subval->type == STRING_VALUE) { + errStr = Pk11Install_PlatformName_Generate( + &_this->forwardCompatible[i], subval->string); + if(errStr) { + goto loser; + } + } + } + Pk11Install_ListIter_delete(subiter); + PR_Free(subiter); + subiter = NULL; + } else if(!PORT_Strcasecmp(pair->key, PLATFORMS_STRING)) { + subiter = Pk11Install_ListIter_new(pair->list); + _this->numPlatforms = pair->list->numPairs; + _this->platforms = (Pk11Install_Platform*) + PR_Malloc(sizeof(Pk11Install_Platform)* + _this->numPlatforms); + for(i=0; i < _this->numPlatforms; i++, + Pk11Install_ListIter_nextItem(subiter)) { + Pk11Install_Platform_init(&_this->platforms[i]); + subval = subiter->current; + if(subval->type == PAIR_VALUE) { + errStr = Pk11Install_Platform_Generate(&_this->platforms[i],subval->pair); + if(errStr) { + goto loser; + } + } + } + Pk11Install_ListIter_delete(subiter); + PR_Free(subiter); + subiter = NULL; + } + } + } + + if(_this->numPlatforms == 0) { + errStr = PR_smprintf(errString[NO_PLATFORMS]); + goto loser; + } + +/* + // + // Now process equivalent platforms + // + + // First the naive pass +*/ + for(i=0; i < _this->numPlatforms; i++) { + if(_this->platforms[i].usesEquiv) { + _this->platforms[i].equiv = NULL; + for(j=0; j < _this->numPlatforms; j++) { + if (Pk11Install_PlatformName_equal(&_this->platforms[i].equivName, + &_this->platforms[j].name)) { + if(i==j) { + errStr = PR_smprintf(errString[EQUIV_LOOP], + Pk11Install_PlatformName_GetString(&_this->platforms[i].name)); + goto loser; + } + _this->platforms[i].equiv = &_this->platforms[j]; + break; + } + } + if(_this->platforms[i].equiv == NULL) { + errStr = PR_smprintf(errString[BOGUS_EQUIV], + Pk11Install_PlatformName_GetString(&_this->platforms[i].name)); + goto loser; + } + } + } + +/* + // Now the intelligent pass, which will also detect loops. + // We will send two pointers through the linked list of equivalent + // platforms. Both start with the current node. "first" traverses + // two nodes for each iteration. "second" lags behind, only traversing + // one node per iteration. Eventually one of two things will happen: + // first will hit the end of the list (a platform that doesn't use + // an equivalency), or first will equal second if there is a loop. +*/ + for(i=0; i < _this->numPlatforms; i++) { + if(_this->platforms[i].usesEquiv) { + second = _this->platforms[i].equiv; + if(!second->usesEquiv) { + /* The first link is the terminal node */ + continue; + } + first = second->equiv; + while(first->usesEquiv) { + if(first == second) { + errStr = PR_smprintf(errString[EQUIV_LOOP], + Pk11Install_PlatformName_GetString(&_this->platforms[i].name)); + goto loser; + } + first = first->equiv; + if(!first->usesEquiv) { + break; + } + if(first == second) { + errStr = PR_smprintf(errString[EQUIV_LOOP], + Pk11Install_PlatformName_GetString(&_this->platforms[i].name)); + goto loser; + } + second = second->equiv; + first = first->equiv; + } + _this->platforms[i].equiv = first; + } + } + +loser: + if(iter) { + Pk11Install_ListIter_delete(iter); + PR_Free(iter); + iter = NULL; + } + if(subiter) { + Pk11Install_ListIter_delete(subiter); + PR_Free(subiter); + subiter = NULL; + } + return errStr; +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: GetBestPlatform +// Class: Pk11Install_Info +// Takes: char *myPlatform, the platform we are currently running +// on. +*/ +Pk11Install_Platform* +Pk11Install_Info_GetBestPlatform(Pk11Install_Info* _this, char *myPlatform) +{ + Pk11Install_PlatformName plat; + char *errStr; + int i, j; + + errStr=NULL; + + Pk11Install_PlatformName_init(&plat); + if( (errStr=Pk11Install_PlatformName_Generate(&plat, myPlatform)) ) { + PR_smprintf_free(errStr); + return NULL; + } + + /* First try real platforms */ + for(i=0; i < _this->numPlatforms; i++) { + if(Pk11Install_PlatformName_equal(&_this->platforms[i].name,&plat)) { + if(_this->platforms[i].equiv) { + return _this->platforms[i].equiv; + } + else { + return &_this->platforms[i]; + } + } + } + + /* Now try forward compatible platforms */ + for(i=0; i < _this->numForwardCompatible; i++) { + if(Pk11Install_PlatformName_lteq(&_this->forwardCompatible[i],&plat)) { + break; + } + } + if(i == _this->numForwardCompatible) { + return NULL; + } + + /* Got a forward compatible name, find the actual platform. */ + for(j=0; j < _this->numPlatforms; j++) { + if(Pk11Install_PlatformName_equal(&_this->platforms[j].name, + &_this->forwardCompatible[i])) { + if(_this->platforms[j].equiv) { + return _this->platforms[j].equiv; + } else { + return &_this->platforms[j]; + } + } + } + + return NULL; +} + +/* +////////////////////////////////////////////////////////////////////////// +// Method: Print +// Class: Pk11Install_Info +*/ +void +Pk11Install_Info_Print(Pk11Install_Info* _this, int pad) +{ + int i; + + PAD(pad); printf("Forward Compatible:\n"); + for(i = 0; i < _this->numForwardCompatible; i++) { + Pk11Install_PlatformName_Print(&_this->forwardCompatible[i],pad+PADINC); + PAD(pad); printf("-------------------\n"); + } + PAD(pad); printf("Platforms:\n"); + for( i = 0; i < _this->numPlatforms; i++) { + Pk11Install_Platform_Print(&_this->platforms[i],pad+PADINC); + PAD(pad); printf("-------------------\n"); + } +} + +/* +////////////////////////////////////////////////////////////////////////// +*/ +static char* +PR_Strdup(const char* str) +{ + char *tmp; + tmp = (char*) PR_Malloc((unsigned int)(strlen(str)+1)); + strcpy(tmp, str); + return tmp; +} + +/* The global value list, the top of the tree */ +Pk11Install_ValueList* Pk11Install_valueList=NULL; + +/****************************************************************************/ +void +Pk11Install_ValueList_AddItem(Pk11Install_ValueList* _this, + Pk11Install_Value *item) +{ + _this->numItems++; + if (item->type == STRING_VALUE) { + _this->numStrings++; + } else { + _this->numPairs++; + } + item->next = _this->head; + _this->head = item; +} + +/****************************************************************************/ +Pk11Install_ListIter* +Pk11Install_ListIter_new_default() +{ + Pk11Install_ListIter* new_this; + new_this = (Pk11Install_ListIter*) + PR_Malloc(sizeof(Pk11Install_ListIter)); + Pk11Install_ListIter_init(new_this); + return new_this; +} + +/****************************************************************************/ +void +Pk11Install_ListIter_init(Pk11Install_ListIter* _this) +{ + _this->list = NULL; + _this->current = NULL; +} + +/****************************************************************************/ +Pk11Install_ListIter* +Pk11Install_ListIter_new(const Pk11Install_ValueList *_list) +{ + Pk11Install_ListIter* new_this; + new_this = (Pk11Install_ListIter*) + PR_Malloc(sizeof(Pk11Install_ListIter)); + new_this->list = _list; + new_this->current = _list->head; + return new_this; +} + +/****************************************************************************/ +void +Pk11Install_ListIter_delete(Pk11Install_ListIter* _this) +{ + _this->list=NULL; + _this->current=NULL; +} + +/****************************************************************************/ +void +Pk11Install_ListIter_reset(Pk11Install_ListIter* _this) +{ + if(_this->list) { + _this->current = _this->list->head; + } +} + +/*************************************************************************/ +Pk11Install_Value* +Pk11Install_ListIter_nextItem(Pk11Install_ListIter* _this) +{ + if(_this->current) { + _this->current = _this->current->next; + } + + return _this->current; +} + +/****************************************************************************/ +Pk11Install_ValueList* +Pk11Install_ValueList_new() +{ + Pk11Install_ValueList* new_this; + new_this = (Pk11Install_ValueList*) + PR_Malloc(sizeof(Pk11Install_ValueList)); + new_this->numItems = 0; + new_this->numPairs = 0; + new_this->numStrings = 0; + new_this->head = NULL; + return new_this; +} + +/****************************************************************************/ +void +Pk11Install_ValueList_delete(Pk11Install_ValueList* _this) +{ + + Pk11Install_Value *tmp; + Pk11Install_Value *list; + list = _this->head; + + while(list != NULL) { + tmp = list; + list = list->next; + PR_Free(tmp); + } + PR_Free(_this); +} + +/****************************************************************************/ +Pk11Install_Value* +Pk11Install_Value_new_default() +{ + Pk11Install_Value* new_this; + new_this = (Pk11Install_Value*)PR_Malloc(sizeof(Pk11Install_Value)); + new_this->type = STRING_VALUE; + new_this->string = NULL; + new_this->pair = NULL; + new_this->next = NULL; + return new_this; +} + +/****************************************************************************/ +Pk11Install_Value* +Pk11Install_Value_new(ValueType _type, Pk11Install_Pointer ptr) +{ + Pk11Install_Value* new_this; + new_this = Pk11Install_Value_new_default(); + new_this->type = _type; + if(_type == STRING_VALUE) { + new_this->pair = NULL; + new_this->string = ptr.string; + } else { + new_this->string = NULL; + new_this->pair = ptr.pair; + } + return new_this; +} + +/****************************************************************************/ +void +Pk11Install_Value_delete(Pk11Install_Value* _this) +{ + if(_this->type == STRING_VALUE) { + PR_Free(_this->string); + } else { + PR_Free(_this->pair); + } +} + +/****************************************************************************/ +Pk11Install_Pair* +Pk11Install_Pair_new_default() +{ + return Pk11Install_Pair_new(NULL,NULL); +} + +/****************************************************************************/ +Pk11Install_Pair* +Pk11Install_Pair_new(char *_key, Pk11Install_ValueList *_list) +{ + Pk11Install_Pair* new_this; + new_this = (Pk11Install_Pair*)PR_Malloc(sizeof(Pk11Install_Pair)); + new_this->key = _key; + new_this->list = _list; + return new_this; +} + +/****************************************************************************/ +void +Pk11Install_Pair_delete(Pk11Install_Pair* _this) +{ + PR_Free(_this->key); + Pk11Install_ValueList_delete(_this->list); + PR_Free(_this->list); +} + +/*************************************************************************/ +void +Pk11Install_Pair_Print(Pk11Install_Pair* _this, int pad) +{ + while (_this) { + /*PAD(pad); printf("**Pair\n"); + PAD(pad); printf("***Key====\n");*/ + PAD(pad); printf("%s {\n", _this->key); + /*PAD(pad); printf("====\n");*/ + /*PAD(pad); printf("***ValueList\n");*/ + Pk11Install_ValueList_Print(_this->list,pad+PADINC); + PAD(pad); printf("}\n"); + } +} + +/*************************************************************************/ +void +Pk11Install_ValueList_Print(Pk11Install_ValueList* _this, int pad) +{ + Pk11Install_Value *v; + + /*PAD(pad);printf("**Value List**\n");*/ + for(v = _this->head; v != NULL; v=v->next) { + Pk11Install_Value_Print(v,pad); + } +} + +/*************************************************************************/ +void +Pk11Install_Value_Print(Pk11Install_Value* _this, int pad) +{ + /*PAD(pad); printf("**Value, type=%s\n", + type==STRING_VALUE ? "string" : "pair");*/ + if(_this->type==STRING_VALUE) { + /*PAD(pad+PADINC); printf("====\n");*/ + PAD(pad); printf("%s\n", _this->string); + /*PAD(pad+PADINC); printf("====\n");*/ + } else { + Pk11Install_Pair_Print(_this->pair,pad+PADINC); + } +} diff --git a/security/nss/cmd/modutil/install-ds.h b/security/nss/cmd/modutil/install-ds.h new file mode 100644 index 000000000..2311f0928 --- /dev/null +++ b/security/nss/cmd/modutil/install-ds.h @@ -0,0 +1,290 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 INSTALL_DS_H +#define INSTALL_DS_H + +#include <stdio.h> +#include <prio.h> +#include <prmem.h> + +extern PRFileDesc *Pk11Install_FD; +extern int Pk11Install_yylex(); +extern int Pk11Install_yylinenum; +extern char *Pk11Install_yyerrstr; + +typedef enum { STRING_VALUE, PAIR_VALUE } ValueType; + +typedef struct Pk11Install_Pair_str Pk11Install_Pair; +typedef union Pk11Install_Pointer_str Pk11Install_Pointer; +typedef struct Pk11Install_Value_str Pk11Install_Value; +typedef struct Pk11Install_ValueList_str Pk11Install_ValueList; +typedef struct Pk11Install_ListIter_str Pk11Install_ListIter; +typedef struct Pk11Install_File_str Pk11Install_File; +typedef struct Pk11Install_PlatformName_str Pk11Install_PlatformName; +typedef struct Pk11Install_Platform_str Pk11Install_Platform; +typedef struct Pk11Install_Info_str Pk11Install_Info; + +extern Pk11Install_Pointer Pk11Install_yylval; +extern Pk11Install_ValueList* Pk11Install_valueList; + +/* +////////////////////////////////////////////////////////////////////////// +// Pk11Install_Pair +////////////////////////////////////////////////////////////////////////// +*/ + +struct Pk11Install_Pair_str { + char * key; + Pk11Install_ValueList *list; + +}; + +Pk11Install_Pair* +Pk11Install_Pair_new_default(); +Pk11Install_Pair* +Pk11Install_Pair_new( char* _key, Pk11Install_ValueList* _list); +void +Pk11Install_Pair_delete(Pk11Install_Pair* _this); +void +Pk11Install_Pair_Print(Pk11Install_Pair* _this, int pad); + +/* +////////////////////////////////////////////////////////////////////////// +// Pk11Install_Pointer +////////////////////////////////////////////////////////////////////////// +*/ +union Pk11Install_Pointer_str { + Pk11Install_ValueList *list; + Pk11Install_Value *value; + Pk11Install_Pair *pair; + char *string; +}; + +/* +////////////////////////////////////////////////////////////////////////// +// Pk11Install_Value +////////////////////////////////////////////////////////////////////////// +*/ +struct Pk11Install_Value_str { + + ValueType type; + char *string; + Pk11Install_Pair *pair; + struct Pk11Install_Value_str *next; +}; + +Pk11Install_Value* +Pk11Install_Value_new_default(); +Pk11Install_Value* +Pk11Install_Value_new(ValueType _type, Pk11Install_Pointer ptr); +void +Pk11Install_Value_delete(Pk11Install_Value* _this); +void +Pk11Install_Value_Print(Pk11Install_Value* _this, int pad); + +/* +////////////////////////////////////////////////////////////////////////// +// Pk11Install_ValueList +////////////////////////////////////////////////////////////////////////// +*/ +struct Pk11Install_ValueList_str { + int numItems; + int numPairs; + int numStrings; + Pk11Install_Value *head; +}; + +Pk11Install_ValueList* +Pk11Install_ValueList_new(); +void +Pk11Install_ValueList_delete(Pk11Install_ValueList* _this); +void +Pk11Install_ValueList_AddItem(Pk11Install_ValueList* _this, + Pk11Install_Value* item); +void +Pk11Install_ValueList_Print(Pk11Install_ValueList* _this, int pad); + + +/* +////////////////////////////////////////////////////////////////////////// +// Pk11Install_ListIter +////////////////////////////////////////////////////////////////////////// +*/ +struct Pk11Install_ListIter_str { + const Pk11Install_ValueList *list; + Pk11Install_Value *current; +}; + +Pk11Install_ListIter* +Pk11Install_ListIter_new_default(); +void +Pk11Install_ListIter_init(Pk11Install_ListIter* _this); +Pk11Install_ListIter* +Pk11Install_ListIter_new(const Pk11Install_ValueList* _list); +void +Pk11Install_ListIter_delete(Pk11Install_ListIter* _this); +void +Pk11Install_ListIter_reset(Pk11Install_ListIter* _this); +Pk11Install_Value* +Pk11Install_ListIter_nextItem(Pk11Install_ListIter* _this); + +/************************************************************************ + * + * Pk11Install_File + */ +struct Pk11Install_File_str { + char *jarPath; + char *relativePath; + char *absolutePath; + PRBool executable; + int permissions; +}; + +Pk11Install_File* +Pk11Install_File_new(); +void +Pk11Install_File_init(Pk11Install_File* _this); +void +Pk11Install_file_delete(Pk11Install_File* _this); +/*// Parses a syntax tree to obtain all attributes. +// Returns NULL for success, error message if parse error.*/ +char* +Pk11Install_File_Generate(Pk11Install_File* _this, + const Pk11Install_Pair* pair); +void +Pk11Install_File_Print(Pk11Install_File* _this, int pad); +void +Pk11Install_File_Cleanup(Pk11Install_File* _this); + +/************************************************************************ + * + * Pk11Install_PlatformName + */ +struct Pk11Install_PlatformName_str { + char *OS; + char **verString; + int numDigits; + char *arch; +}; + +Pk11Install_PlatformName* +Pk11Install_PlatformName_new(); +void +Pk11Install_PlatformName_init(Pk11Install_PlatformName* _this); +void +Pk11Install_PlatformName_delete(Pk11Install_PlatformName* _this); +char* +Pk11Install_PlatformName_Generate(Pk11Install_PlatformName* _this, + const char* str); +char* +Pk11Install_PlatformName_GetString(Pk11Install_PlatformName* _this); +char* +Pk11Install_PlatformName_GetVerString(Pk11Install_PlatformName* _this); +void +Pk11Install_PlatformName_Print(Pk11Install_PlatformName* _this, int pad); +void +Pk11Install_PlatformName_Cleanup(Pk11Install_PlatformName* _this); +PRBool +Pk11Install_PlatformName_equal(Pk11Install_PlatformName* _this, + Pk11Install_PlatformName* cmp); +PRBool +Pk11Install_PlatformName_lteq(Pk11Install_PlatformName* _this, + Pk11Install_PlatformName* cmp); +PRBool +Pk11Install_PlatformName_lt(Pk11Install_PlatformName* _this, + Pk11Install_PlatformName* cmp); + +/************************************************************************ + * + * Pk11Install_Platform + */ +struct Pk11Install_Platform_str { + Pk11Install_PlatformName name; + Pk11Install_PlatformName equivName; + struct Pk11Install_Platform_str *equiv; + PRBool usesEquiv; + char *moduleFile; + char *moduleName; + int modFile; + unsigned long mechFlags; + unsigned long cipherFlags; + Pk11Install_File *files; + int numFiles; +}; + +Pk11Install_Platform* +Pk11Install_Platform_new(); +void +Pk11Install_Platform_init(Pk11Install_Platform* _this); +void +Pk11Install_Platform_delete(Pk11Install_Platform* _this); +/*// Returns NULL for success, error message if parse error.*/ +char* +Pk11Install_Platform_Generate(Pk11Install_Platform* _this, + const Pk11Install_Pair *pair); +void +Pk11Install_Platform_Print(Pk11Install_Platform* _this, int pad); +void +Pk11Install_Platform_Cleanup(Pk11Install_Platform* _this); + +/************************************************************************ + * + * Pk11Install_Info + */ +struct Pk11Install_Info_str { + Pk11Install_Platform *platforms; + int numPlatforms; + Pk11Install_PlatformName *forwardCompatible; + int numForwardCompatible; +}; + +Pk11Install_Info* +Pk11Install_Info_new(); +void +Pk11Install_Info_init(); +void +Pk11Install_Info_delete(Pk11Install_Info* _this); +/*// Returns NULL for success, error message if parse error.*/ +char* +Pk11Install_Info_Generate(Pk11Install_Info* _this, + const Pk11Install_ValueList *list); + /*// Returns NULL if there is no matching platform*/ +Pk11Install_Platform* +Pk11Install_Info_GetBestPlatform(Pk11Install_Info* _this, char* myPlatform); +void +Pk11Install_Info_Print(Pk11Install_Info* _this, int pad); +void +Pk11Install_Info_Cleanup(Pk11Install_Info* _this); + +#endif /* INSTALL_DS_H */ diff --git a/security/nss/cmd/modutil/install.c b/security/nss/cmd/modutil/install.c new file mode 100644 index 000000000..c6f55be01 --- /dev/null +++ b/security/nss/cmd/modutil/install.c @@ -0,0 +1,985 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "install.h" +#include "install-ds.h" +#include <prlock.h> +#include <prio.h> +#include <prmem.h> +#include <prprf.h> +#include <prsystem.h> +#include <prproces.h> + +#ifdef XP_UNIX +/* for chmod */ +#include <sys/types.h> +#include <sys/stat.h> +#endif + +/*extern "C" {*/ +#include <jar.h> +/*}*/ + +extern /*"C"*/ +int Pk11Install_AddNewModule(char* moduleName, char* dllPath, + unsigned long defaultMechanismFlags, + unsigned long cipherEnableFlags); +extern /*"C"*/ +short Pk11Install_UserVerifyJar(JAR *jar, PRFileDesc *out, + PRBool query); +extern /*"C"*/ +const char* mySECU_ErrorString(int16); +extern +int Pk11Install_yyparse(); + +#define INSTALL_METAINFO_TAG "Pkcs11_install_script" +#define SCRIPT_TEMP_FILE "pkcs11inst.tmp" +#define ROOT_MARKER "%root%" +#define TEMP_MARKER "%temp%" +#define PRINTF_ROOT_MARKER "%%root%%" +#define TEMPORARY_DIRECTORY_NAME "pk11inst.dir" +#define JAR_BASE_END (JAR_BASE+100) + +static PRLock* errorHandlerLock=NULL; +static Pk11Install_ErrorHandler errorHandler=NULL; +static char* PR_Strdup(const char* str); +static int rm_dash_r (char *path); +static int make_dirs(char *path, int file_perms); +static int dir_perms(int perms); + +static Pk11Install_Error DoInstall(JAR *jar, const char *installDir, + const char* tempDir, Pk11Install_Platform *platform, + PRFileDesc *feedback, PRBool noverify); + +static char *errorString[]= { + "Operation was successful", /* PK11_INSTALL_NO_ERROR */ + "Directory \"%s\" does not exist", /* PK11_INSTALL_DIR_DOESNT_EXIST */ + "File \"%s\" does not exist", /* PK11_INSTALL_FILE_DOESNT_EXIST */ + "File \"%s\" is not readable", /* PK11_INSTALL_FILE_NOT_READABLE */ + "%s", /* PK11_INSTALL_ERROR_STRING */ + "Error in JAR file %s: %s", /* PK11_INSTALL_JAR_ERROR */ + "No Pkcs11_install_script specified in JAR metainfo file", + /* PK11_INSTALL_NO_INSTALLER_SCRIPT */ + "Could not delete temporary file \"%s\"", + /*PK11_INSTALL_DELETE_TEMP_FILE */ + "Could not open temporary file \"%s\"", /*PK11_INSTALL_OPEN_SCRIPT_FILE*/ + "%s: %s", /* PK11_INSTALL_SCRIPT_PARSE */ + "Error in script: %s", + "Unable to obtain system platform information", + "Installer script has no information about the current platform (%s)", + "Relative directory \"%s\" does not contain "PRINTF_ROOT_MARKER, + "Module File \"%s\" not found", + "Error occurred installing module \"%s\" into database", + "Error extracting \"%s\" from JAR file: %s", + "Directory \"%s\" is not writeable", + "Could not create directory \"%s\"", + "Could not remove directory \"%s\"", + "Unable to execute \"%s\"", + "Unable to wait for process \"%s\"", + "\"%s\" returned error code %d", + "User aborted operation", + "Unspecified error" +}; + +enum { + INSTALLED_FILE_MSG=0, + INSTALLED_MODULE_MSG, + INSTALLER_SCRIPT_NAME, + MY_PLATFORM_IS, + USING_PLATFORM, + PARSED_INSTALL_SCRIPT, + EXEC_FILE_MSG, + EXEC_SUCCESS, + INSTALLATION_COMPLETE_MSG, + USER_ABORT +}; + +static char *msgStrings[] = { + "Installed file %s to %s\n", + "Installed module \"%s\" into module database\n", + "Using installer script \"%s\"\n", + "Current platform is %s\n", + "Using installation parameters for platform %s\n", + "Successfully parsed installation script\n", + "Executing \"%s\"...\n", + "\"%s\" executed successfully\n", + "\nInstallation completed successfully\n", + "\nAborting...\n" +}; + +/************************************************************************** + * S t r i n g N o d e + */ +typedef struct StringNode_str { + char *str; + struct StringNode_str* next; +} StringNode; + +StringNode* StringNode_new() +{ + StringNode* new_this; + new_this = (StringNode*)malloc(sizeof(StringNode)); + new_this->str=NULL; + new_this->next=NULL; + return new_this; +} + +void StringNode_delete(StringNode* s) +{ + if(s->str) { + PR_Free(s->str); + s->str=NULL; + } +} + +/************************************************************************* + * S t r i n g L i s t + */ +typedef struct StringList_str { + StringNode* head; + StringNode* tail; +} StringList; + +void StringList_new(StringList* list) +{ + list->head=NULL; + list->tail=NULL; +} + +void StringList_delete(StringList* list) +{ + StringNode *tmp; + while(list->head) { + tmp = list->head; + list->head = list->head->next; + StringNode_delete(tmp); + } +} + +void +StringList_Append(StringList* list, char* str) +{ + if(!str) { + return; + } + + if(!list->tail) { + /* This is the first element */ + list->head = list->tail = StringNode_new(); + } else { + list->tail->next = StringNode_new(); + list->tail = list->tail->next; + } + + list->tail->str = PR_Strdup(str); + list->tail->next = NULL; /* just to be sure */ +} + +/************************************************************************** + * + * P k 1 1 I n s t a l l _ S e t E r r o r H a n d l e r + * + * Sets the error handler to be used by the library. Returns the current + * error handler function. + */ +Pk11Install_ErrorHandler +Pk11Install_SetErrorHandler(Pk11Install_ErrorHandler handler) +{ + Pk11Install_ErrorHandler old; + + if(!errorHandlerLock) { + errorHandlerLock = PR_NewLock(); + } + + PR_Lock(errorHandlerLock); + + old = errorHandler; + errorHandler = handler; + + PR_Unlock(errorHandlerLock); + + return old; +} + +/************************************************************************** + * + * P k 1 1 I n s t a l l _ I n i t + * + * Does initialization that otherwise would be done on the fly. Only + * needs to be called by multithreaded apps, before they make any calls + * to this library. + */ +void +Pk11Install_Init() +{ + if(!errorHandlerLock) { + errorHandlerLock = PR_NewLock(); + } +} + +/************************************************************************** + * + * P k 1 1 I n s t a l l _ R e l e a s e + * + * Releases static data structures used by the library. Don't use the + * library after calling this, unless you call Pk11Install_Init() + * first. This function doesn't have to be called at all unless you're + * really anal about freeing memory before your program exits. + */ +void +Pk11Install_Release() +{ + if(errorHandlerLock) { + PR_Free(errorHandlerLock); + errorHandlerLock = NULL; + } +} + +/************************************************************************* + * + * e r r o r + * + * Takes an error code and its arguments, creates the error string, + * and sends the string to the handler function if it exists. + */ + +#ifdef OSF1 +/* stdarg has already been pulled in from NSPR */ +#undef va_start +#undef va_end +#undef va_arg +#include <varargs.h> +#else +#include <stdarg.h> +#endif + +#ifdef OSF1 +static void +error(long va_alist, ...) +#else +static void +error(Pk11Install_Error errcode, ...) +#endif +{ + + va_list ap; + char *errstr; + Pk11Install_ErrorHandler handler; + + if(!errorHandlerLock) { + errorHandlerLock = PR_NewLock(); + } + + PR_Lock(errorHandlerLock); + + handler = errorHandler; + + PR_Unlock(errorHandlerLock); + + if(handler) { +#ifdef OSF1 + va_start(ap); + errstr = PR_vsmprintf(errorString[va_arg(ap, Pk11Install_Error)], ap); +#else + va_start(ap, errcode); + errstr = PR_vsmprintf(errorString[errcode], ap); +#endif + handler(errstr); + PR_smprintf_free(errstr); + va_end(ap); + } +} + +/************************************************************************* + * + * j a r _ c a l l b a c k + */ +static int +jar_callback(int status, JAR *foo, const char *bar, char *pathname, + char *errortext) { + char *string; + + string = PR_smprintf("JAR error %d: %s in file %s\n", status, errortext, + pathname); + error(PK11_INSTALL_ERROR_STRING, string); + PR_smprintf_free(string); + return 0; +} + +/************************************************************************* + * + * P k 1 1 I n s t a l l _ D o I n s t a l l + * + * jarFile is the path of a JAR in the PKCS #11 module JAR format. + * installDir is the directory relative to which files will be + * installed. + */ +Pk11Install_Error +Pk11Install_DoInstall(char *jarFile, const char *installDir, + const char *tempDir, PRFileDesc *feedback, short force, PRBool noverify) +{ + JAR *jar; + char *installer; + unsigned long installer_len; + int status; + Pk11Install_Error ret; + PRBool made_temp_file; + Pk11Install_Info installInfo; + Pk11Install_Platform *platform; + char* errMsg; + char sysname[SYS_INFO_BUFFER_LENGTH], release[SYS_INFO_BUFFER_LENGTH], + arch[SYS_INFO_BUFFER_LENGTH]; + char *myPlatform; + + jar=NULL; + ret = PK11_INSTALL_UNSPECIFIED; + made_temp_file=PR_FALSE; + errMsg=NULL; + Pk11Install_Info_init(&installInfo); + + /* + printf("Inside DoInstall, jarFile=%s, installDir=%s, tempDir=%s\n", + jarFile, installDir, tempDir); + */ + + /* + * Check out jarFile and installDir for validity + */ + if( PR_Access(installDir, PR_ACCESS_EXISTS) != PR_SUCCESS ) { + error(PK11_INSTALL_DIR_DOESNT_EXIST, installDir); + return PK11_INSTALL_DIR_DOESNT_EXIST; + } + if(!tempDir) { + tempDir = "."; + } + if( PR_Access(tempDir, PR_ACCESS_EXISTS) != PR_SUCCESS ) { + error(PK11_INSTALL_DIR_DOESNT_EXIST, tempDir); + return PK11_INSTALL_DIR_DOESNT_EXIST; + } + if( PR_Access(tempDir, PR_ACCESS_WRITE_OK) != PR_SUCCESS ) { + error(PK11_INSTALL_DIR_NOT_WRITEABLE, tempDir); + return PK11_INSTALL_DIR_NOT_WRITEABLE; + } + if( (PR_Access(jarFile, PR_ACCESS_EXISTS) != PR_SUCCESS) ) { + error(PK11_INSTALL_FILE_DOESNT_EXIST, jarFile); + return PK11_INSTALL_FILE_DOESNT_EXIST; + } + if( PR_Access(jarFile, PR_ACCESS_READ_OK) != PR_SUCCESS ) { + error(PK11_INSTALL_FILE_NOT_READABLE, jarFile); + return PK11_INSTALL_FILE_NOT_READABLE; + } + + /* + * Extract the JAR file + */ + jar = JAR_new(); + JAR_set_callback(JAR_CB_SIGNAL, jar, jar_callback); + + if(noverify) { + status = JAR_pass_archive_unverified(jar, jarArchGuess, jarFile, "url"); + } else { + status = JAR_pass_archive(jar, jarArchGuess, jarFile, "url"); + } + if( (status < 0) || (jar->valid < 0) ) { + if (status >= JAR_BASE && status <= JAR_BASE_END) { + error(PK11_INSTALL_JAR_ERROR, jarFile, JAR_get_error(status)); + } else { + error(PK11_INSTALL_JAR_ERROR, jarFile, + mySECU_ErrorString((int16) PORT_GetError()) ); + } + ret=PK11_INSTALL_JAR_ERROR; + goto loser; + } + /*printf("passed the archive\n");*/ + + /* + * Show the user security information, allow them to abort or continue + */ + if( Pk11Install_UserVerifyJar(jar, PR_STDOUT, + force?PR_FALSE:PR_TRUE) && !force) { + if(feedback) { + PR_fprintf(feedback, msgStrings[USER_ABORT]); + } + ret=PK11_INSTALL_USER_ABORT; + goto loser; + } + + /* + * Get the name of the installation file + */ + if( JAR_get_metainfo(jar, NULL, INSTALL_METAINFO_TAG, (void**)&installer, + (unsigned long*)&installer_len) ) { + error(PK11_INSTALL_NO_INSTALLER_SCRIPT); + ret=PK11_INSTALL_NO_INSTALLER_SCRIPT; + goto loser; + } + if(feedback) { + PR_fprintf(feedback, msgStrings[INSTALLER_SCRIPT_NAME], installer); + } + + /* + * Extract the installation file + */ + if( PR_Access(SCRIPT_TEMP_FILE, PR_ACCESS_EXISTS) == PR_SUCCESS) { + if( PR_Delete(SCRIPT_TEMP_FILE) != PR_SUCCESS) { + error(PK11_INSTALL_DELETE_TEMP_FILE, SCRIPT_TEMP_FILE); + ret=PK11_INSTALL_DELETE_TEMP_FILE; + goto loser; + } + } + if(noverify) { + status = JAR_extract(jar, installer, SCRIPT_TEMP_FILE); + } else { + status = JAR_verified_extract(jar, installer, SCRIPT_TEMP_FILE); + } + if(status) { + if (status >= JAR_BASE && status <= JAR_BASE_END) { + error(PK11_INSTALL_JAR_EXTRACT, installer, JAR_get_error(status)); + } else { + error(PK11_INSTALL_JAR_EXTRACT, installer, + mySECU_ErrorString((int16) PORT_GetError()) ); + } + ret = PK11_INSTALL_JAR_EXTRACT; + goto loser; + } else { + made_temp_file = PR_TRUE; + } + + /* + * Parse the installation file into a syntax tree + */ + Pk11Install_FD = PR_Open(SCRIPT_TEMP_FILE, PR_RDONLY, 0); + if(!Pk11Install_FD) { + error(PK11_INSTALL_OPEN_SCRIPT_FILE, SCRIPT_TEMP_FILE); + ret=PK11_INSTALL_OPEN_SCRIPT_FILE; + goto loser; + } + if(Pk11Install_yyparse()) { + error(PK11_INSTALL_SCRIPT_PARSE, installer, + Pk11Install_yyerrstr ? Pk11Install_yyerrstr : ""); + ret=PK11_INSTALL_SCRIPT_PARSE; + goto loser; + } + +#if 0 + /* for debugging */ + Pk11Install_valueList->Print(0); +#endif + + /* + * From the syntax tree, build a semantic structure + */ + errMsg = Pk11Install_Info_Generate(&installInfo,Pk11Install_valueList); + if(errMsg) { + error(PK11_INSTALL_SEMANTIC, errMsg); + ret=PK11_INSTALL_SEMANTIC; + goto loser; + } +#if 0 + installInfo.Print(0); +#endif + + if(feedback) { + PR_fprintf(feedback, msgStrings[PARSED_INSTALL_SCRIPT]); + } + + /* + * Figure out which platform to use + */ + { + sysname[0] = release[0] = arch[0] = '\0'; + + if( (PR_GetSystemInfo(PR_SI_SYSNAME, sysname, SYS_INFO_BUFFER_LENGTH) + != PR_SUCCESS) || + (PR_GetSystemInfo(PR_SI_RELEASE, release, SYS_INFO_BUFFER_LENGTH) + != PR_SUCCESS) || + (PR_GetSystemInfo(PR_SI_ARCHITECTURE, arch, SYS_INFO_BUFFER_LENGTH) + != PR_SUCCESS) ) { + error(PK11_INSTALL_SYSINFO); + ret=PK11_INSTALL_SYSINFO; + goto loser; + } + myPlatform = PR_smprintf("%s:%s:%s", sysname, release, arch); + platform = Pk11Install_Info_GetBestPlatform(&installInfo,myPlatform); + if(!platform) { + error(PK11_INSTALL_NO_PLATFORM, myPlatform); + PR_smprintf_free(myPlatform); + ret=PK11_INSTALL_NO_PLATFORM; + goto loser; + } + if(feedback) { + PR_fprintf(feedback, msgStrings[MY_PLATFORM_IS], myPlatform); + PR_fprintf(feedback, msgStrings[USING_PLATFORM], + Pk11Install_PlatformName_GetString(&platform->name)); + } + PR_smprintf_free(myPlatform); + } + + /* Run the install for that platform */ + ret = DoInstall(jar, installDir, tempDir, platform, feedback, noverify); + if(ret) { + goto loser; + } + + ret = PK11_INSTALL_SUCCESS; +loser: + if(Pk11Install_valueList) { + Pk11Install_ValueList_delete(Pk11Install_valueList); + PR_Free(Pk11Install_valueList); + Pk11Install_valueList = NULL; + } + if(jar) { + JAR_destroy(jar); + } + if(made_temp_file) { + PR_Delete(SCRIPT_TEMP_FILE); + } + if(errMsg) { + PR_smprintf_free(errMsg); + } + return ret; +} + +/* +///////////////////////////////////////////////////////////////////////// +// actually run the installation, copying files to and fro +*/ +static Pk11Install_Error +DoInstall(JAR *jar, const char *installDir, const char *tempDir, + Pk11Install_Platform *platform, PRFileDesc *feedback, PRBool noverify) +{ + Pk11Install_File *file; + Pk11Install_Error ret; + char *reldir; + char *dest; + char *modDest; + char *cp; + int i; + int status; + char *tempname, *temp; + StringList executables; + StringNode *execNode; + PRProcessAttr *attr; + PRProcess *proc; + char *argv[2]; + char *envp[1]; + int errcode; + + ret=PK11_INSTALL_UNSPECIFIED; + reldir=NULL; + dest=NULL; + modDest=NULL; + tempname=NULL; + + StringList_new(&executables); + /* + // Create Temporary directory + */ + tempname = PR_smprintf("%s/%s", tempDir, TEMPORARY_DIRECTORY_NAME); + if( PR_Access(tempname, PR_ACCESS_EXISTS)==PR_SUCCESS ) { + /* Left over from previous run? Delete it. */ + rm_dash_r(tempname); + } + if(PR_MkDir(tempname, 0700) != PR_SUCCESS) { + error(PK11_INSTALL_CREATE_DIR, tempname); + ret = PK11_INSTALL_CREATE_DIR; + goto loser; + } + + /* + // Install all the files + */ + for(i=0; i < platform->numFiles; i++) { + file = &platform->files[i]; + + if(file->relativePath) { + PRBool foundMarker = PR_FALSE; + reldir = PR_Strdup(file->relativePath); + + /* Replace all the markers with the directories for which they stand */ + while(1) { + if( (cp=PL_strcasestr(reldir, ROOT_MARKER)) ) { + /* Has a %root% marker */ + *cp = '\0'; + temp = PR_smprintf("%s%s%s", reldir, installDir, + cp+strlen(ROOT_MARKER)); + PR_Free(reldir); + reldir = temp; + foundMarker = PR_TRUE; + } else if( (cp = PL_strcasestr(reldir, TEMP_MARKER)) ) { + /* Has a %temp% marker */ + *cp = '\0'; + temp = PR_smprintf("%s%s%s", reldir, tempname, + cp+strlen(TEMP_MARKER)); + PR_Free(reldir); + reldir = temp; + foundMarker = PR_TRUE; + } else { + break; + } + } + if(!foundMarker) { + /* Has no markers...this isn't really a relative directory */ + error(PK11_INSTALL_BOGUS_REL_DIR, file->relativePath); + ret = PK11_INSTALL_BOGUS_REL_DIR; + goto loser; + } + dest = reldir; + reldir = NULL; + } else if(file->absolutePath) { + dest = PR_Strdup(file->absolutePath); + } + + /* Remember if this is the module file, we'll need to add it later */ + if(i == platform->modFile) { + modDest = PR_Strdup(dest); + } + + /* Remember is this is an executable, we'll need to run it later */ + if(file->executable) { + StringList_Append(&executables,dest); + /*executables.Append(dest);*/ + } + + /* Make sure the directory we are targetting exists */ + if( make_dirs(dest, file->permissions) ) { + ret=PK11_INSTALL_CREATE_DIR; + goto loser; + } + + /* Actually extract the file onto the filesystem */ + if(noverify) { + status = JAR_extract(jar, (char*)file->jarPath, dest); + } else { + status = JAR_verified_extract(jar, (char*)file->jarPath, dest); + } + if(status) { + if (status >= JAR_BASE && status <= JAR_BASE_END) { + error(PK11_INSTALL_JAR_EXTRACT, file->jarPath, + JAR_get_error(status)); + } else { + error(PK11_INSTALL_JAR_EXTRACT, file->jarPath, + mySECU_ErrorString((int16) PORT_GetError()) ); + } + ret=PK11_INSTALL_JAR_EXTRACT; + goto loser; + } + if(feedback) { + PR_fprintf(feedback, msgStrings[INSTALLED_FILE_MSG], + file->jarPath, dest); + } + + /* no NSPR command to change permissions? */ +#ifdef XP_UNIX + chmod(dest, file->permissions); +#endif + + /* Memory clean-up tasks */ + if(reldir) { + PR_Free(reldir); + reldir = NULL; + } + if(dest) { + PR_Free(dest); + dest = NULL; + } + } + /* Make sure we found the module file */ + if(!modDest) { + /* Internal problem here, since every platform is supposed to have + a module file */ + error(PK11_INSTALL_NO_MOD_FILE, platform->moduleName); + ret=PK11_INSTALL_NO_MOD_FILE; + goto loser; + } + + /* + // Execute any executable files + */ + { + argv[1] = NULL; + envp[0] = NULL; + for(execNode = executables.head; execNode; execNode = execNode->next) { + attr = PR_NewProcessAttr(); + argv[0] = PR_Strdup(execNode->str); + + /* Announce our intentions */ + if(feedback) { + PR_fprintf(feedback, msgStrings[EXEC_FILE_MSG], execNode->str); + } + + /* start the process */ + if( !(proc=PR_CreateProcess(execNode->str, argv, envp, attr)) ) { + PR_Free(argv[0]); + PR_DestroyProcessAttr(attr); + error(PK11_INSTALL_EXEC_FILE, execNode->str); + ret=PK11_INSTALL_EXEC_FILE; + goto loser; + } + + /* wait for it to finish */ + if( PR_WaitProcess(proc, &errcode) != PR_SUCCESS) { + PR_Free(argv[0]); + PR_DestroyProcessAttr(attr); + error(PK11_INSTALL_WAIT_PROCESS, execNode->str); + ret=PK11_INSTALL_WAIT_PROCESS; + goto loser; + } + + /* What happened? */ + if(errcode) { + /* process returned an error */ + error(PK11_INSTALL_PROC_ERROR, execNode->str, errcode); + } else if(feedback) { + /* process ran successfully */ + PR_fprintf(feedback, msgStrings[EXEC_SUCCESS], execNode->str); + } + + PR_Free(argv[0]); + PR_DestroyProcessAttr(attr); + } + } + + /* + // Add the module + */ + status = Pk11Install_AddNewModule((char*)platform->moduleName, + (char*)modDest, platform->mechFlags, platform->cipherFlags ); + + if(status != SECSuccess) { + error(PK11_INSTALL_ADD_MODULE, platform->moduleName); + ret=PK11_INSTALL_ADD_MODULE; + goto loser; + } + if(feedback) { + PR_fprintf(feedback, msgStrings[INSTALLED_MODULE_MSG], + platform->moduleName); + } + + if(feedback) { + PR_fprintf(feedback, msgStrings[INSTALLATION_COMPLETE_MSG]); + } + + ret = PK11_INSTALL_SUCCESS; + +loser: + if(reldir) { + PR_Free(reldir); + } + if(dest) { + PR_Free(dest); + } + if(modDest) { + PR_Free(modDest); + } + if(tempname) { + PRFileInfo info; + if(PR_GetFileInfo(tempname, &info) == PR_SUCCESS) { + if((info.type == PR_FILE_DIRECTORY)) { + /* Recursively remove temporary directory */ + if(rm_dash_r(tempname)) { + error(PK11_INSTALL_REMOVE_DIR, + tempname); + ret=PK11_INSTALL_REMOVE_DIR; + } + + } + } + PR_Free(tempname); + } + StringList_delete(&executables); + return ret; +} + +/* +////////////////////////////////////////////////////////////////////////// +*/ +static char* +PR_Strdup(const char* str) +{ + char *tmp = (char*) PR_Malloc(strlen(str)+1); + strcpy(tmp, str); + return tmp; +} + +/* + * r m _ d a s h _ r + * + * Remove a file, or a directory recursively. + * + */ +static int +rm_dash_r (char *path) +{ + PRDir *dir; + PRDirEntry *entry; + PRFileInfo fileinfo; + char filename[240]; + + if(PR_GetFileInfo(path, &fileinfo) != PR_SUCCESS) { + /*fprintf(stderr, "Error: Unable to access %s\n", filename);*/ + return -1; + } + if(fileinfo.type == PR_FILE_DIRECTORY) { + + dir = PR_OpenDir(path); + if(!dir) { + return -1; + } + + /* Recursively delete all entries in the directory */ + while((entry = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) { + sprintf(filename, "%s/%s", path, entry->name); + if(rm_dash_r(filename)) return -1; + } + + if(PR_CloseDir(dir) != PR_SUCCESS) { + return -1; + } + + /* Delete the directory itself */ + if(PR_RmDir(path) != PR_SUCCESS) { + return -1; + } + } else { + if(PR_Delete(path) != PR_SUCCESS) { + return -1; + } + } + return 0; +} + +/*************************************************************************** + * + * m a k e _ d i r s + * + * Ensure that the directory portion of the path exists. This may require + * making the directory, and its parent, and its parent's parent, etc. + */ +static int +make_dirs(char *path, int file_perms) +{ + char *Path; + char *start; + char *sep; + int ret = 0; + PRFileInfo info; + + if(!path) { + return 0; + } + + Path = PR_Strdup(path); + start = strpbrk(Path, "/\\"); + if(!start) { + return 0; + } + start++; /* start right after first slash */ + + /* Each time through the loop add one more directory. */ + while( (sep=strpbrk(start, "/\\")) ) { + *sep = '\0'; + + if( PR_GetFileInfo(Path, &info) != PR_SUCCESS) { + /* No such dir, we have to create it */ + if( PR_MkDir(Path, dir_perms(file_perms)) != PR_SUCCESS) { + error(PK11_INSTALL_CREATE_DIR, Path); + ret = PK11_INSTALL_CREATE_DIR; + goto loser; + } + } else { + /* something exists by this name, make sure it's a directory */ + if( info.type != PR_FILE_DIRECTORY ) { + error(PK11_INSTALL_CREATE_DIR, Path); + ret = PK11_INSTALL_CREATE_DIR; + goto loser; + } + } + + /* If this is the lowest directory level, make sure it is writeable */ + if(!strpbrk(sep+1, "/\\")) { + if( PR_Access(Path, PR_ACCESS_WRITE_OK)!=PR_SUCCESS) { + error(PK11_INSTALL_DIR_NOT_WRITEABLE, Path); + ret = PK11_INSTALL_DIR_NOT_WRITEABLE; + goto loser; + } + } + + start = sep+1; /* start after the next slash */ + *sep = '/'; + } + +loser: + PR_Free(Path); + return ret; +} + +/************************************************************************* + * d i r _ p e r m s + * + * Guesses the desired permissions on a directory based on the permissions + * of a file that will be stored in it. Give read, write, and + * execute to the owner (so we can create the file), read and + * execute to anyone who has read permissions on the file, and write + * to anyone who has write permissions on the file. + */ +static int +dir_perms(int perms) +{ + int ret = 0; + + /* owner */ + ret |= 0700; + + /* group */ + if(perms & 0040) { + /* read on the file -> read and execute on the directory */ + ret |= 0050; + } + if(perms & 0020) { + /* write on the file -> write on the directory */ + ret |= 0020; + } + + /* others */ + if(perms & 0004) { + /* read on the file -> read and execute on the directory */ + ret |= 0005; + } + if(perms & 0002) { + /* write on the file -> write on the directory */ + ret |= 0002; + } + + return ret; +} diff --git a/security/nss/cmd/modutil/install.h b/security/nss/cmd/modutil/install.h new file mode 100644 index 000000000..3874ed77e --- /dev/null +++ b/security/nss/cmd/modutil/install.h @@ -0,0 +1,130 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 PK11INSTALL_H +#define PK11INSTALL_H + +#include <prio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void (*Pk11Install_ErrorHandler)(char *); + +typedef enum { + PK11_INSTALL_NO_ERROR=0, + PK11_INSTALL_DIR_DOESNT_EXIST, + PK11_INSTALL_FILE_DOESNT_EXIST, + PK11_INSTALL_FILE_NOT_READABLE, + PK11_INSTALL_ERROR_STRING, + PK11_INSTALL_JAR_ERROR, + PK11_INSTALL_NO_INSTALLER_SCRIPT, + PK11_INSTALL_DELETE_TEMP_FILE, + PK11_INSTALL_OPEN_SCRIPT_FILE, + PK11_INSTALL_SCRIPT_PARSE, + PK11_INSTALL_SEMANTIC, + PK11_INSTALL_SYSINFO, + PK11_INSTALL_NO_PLATFORM, + PK11_INSTALL_BOGUS_REL_DIR, + PK11_INSTALL_NO_MOD_FILE, + PK11_INSTALL_ADD_MODULE, + PK11_INSTALL_JAR_EXTRACT, + PK11_INSTALL_DIR_NOT_WRITEABLE, + PK11_INSTALL_CREATE_DIR, + PK11_INSTALL_REMOVE_DIR, + PK11_INSTALL_EXEC_FILE, + PK11_INSTALL_WAIT_PROCESS, + PK11_INSTALL_PROC_ERROR, + PK11_INSTALL_USER_ABORT, + PK11_INSTALL_UNSPECIFIED +} Pk11Install_Error; +#define PK11_INSTALL_SUCCESS PK11_INSTALL_NO_ERROR + +/************************************************************************** + * + * P k 1 1 I n s t a l l _ I n i t + * + * Does initialization that otherwise would be done on the fly. Only + * needs to be called by multithreaded apps, before they make any calls + * to this library. + */ +void +Pk11Install_Init(); + +/************************************************************************** + * + * P k 1 1 I n s t a l l _ S e t E r r o r H a n d l e r + * + * Sets the error handler to be used by the library. Returns the current + * error handler function. + */ +Pk11Install_ErrorHandler +Pk11Install_SetErrorHandler(Pk11Install_ErrorHandler handler); + + +/************************************************************************** + * + * P k 1 1 I n s t a l l _ R e l e a s e + * + * Releases static data structures used by the library. Don't use the + * library after calling this, unless you call Pk11Install_Init() + * first. This function doesn't have to be called at all unless you're + * really anal about freeing memory before your program exits. + */ +void +Pk11Install_Release(); + +/************************************************************************* + * + * P k 1 1 I n s t a l l _ D o I n s t a l l + * + * jarFile is the path of a JAR in the PKCS #11 module JAR format. + * installDir is the directory relative to which files will be + * installed. + * feedback is a file descriptor to which to write informative (not error) + * status messages: what files are being installed, what modules are being + * installed. If feedback==NULL, no messages will be displayed. + * If force != 0, interactive prompts will be suppressed. + * If noverify == PR_TRUE, signatures won't be checked on the JAR file. + */ +Pk11Install_Error +Pk11Install_DoInstall(char *jarFile, const char *installDir, + const char *tempDir, PRFileDesc *feedback, short force, + PRBool noverify); + +#ifdef __cplusplus +} +#endif + +#endif /*PK11INSTALL_H*/ diff --git a/security/nss/cmd/modutil/installparse.c b/security/nss/cmd/modutil/installparse.c new file mode 100644 index 000000000..16f81b6eb --- /dev/null +++ b/security/nss/cmd/modutil/installparse.c @@ -0,0 +1,429 @@ +#ifndef lint +char yysccsid[] = "@(#)yaccpar 1.4 (Berkeley) 02/25/90"; +#endif +#line 37 "installparse.y" + +#define yyparse Pk11Install_yyparse +#define yylex Pk11Install_yylex +#define yyerror Pk11Install_yyerror +#define yychar Pk11Install_yychar +#define yyval Pk11Install_yyval +#define yylval Pk11Install_yylval +#define yydebug Pk11Install_yydebug +#define yynerrs Pk11Install_yynerrs +#define yyerrflag Pk11Install_yyerrflag +#define yyss Pk11Install_yyss +#define yyssp Pk11Install_yyssp +#define yyvs Pk11Install_yyvs +#define yyvsp Pk11Install_yyvsp +#define yylhs Pk11Install_yylhs +#define yylen Pk11Install_yylen +#define yydefred Pk11Install_yydefred +#define yydgoto Pk11Install_yydgoto +#define yysindex Pk11Install_yysindex +#define yyrindex Pk11Install_yyrindex +#define yygindex Pk11Install_yygindex +#define yytable Pk11Install_yytable +#define yycheck Pk11Install_yycheck +#define yyname Pk11Install_yyname +#define yyrule Pk11Install_yyrule + +/* C Stuff */ +#include "install-ds.h" +#include <prprf.h> + +#define YYSTYPE Pk11Install_Pointer +extern char *Pk11Install_yytext; +char *Pk11Install_yyerrstr=NULL; + +#line 40 "ytab.c" +#define OPENBRACE 257 +#define CLOSEBRACE 258 +#define STRING 259 +#define YYERRCODE 256 +short yylhs[] = { -1, + 0, 1, 1, 2, 2, 3, 4, +}; +short yylen[] = { 2, + 1, 2, 0, 1, 1, 4, 1, +}; +short yydefred[] = { 0, + 0, 0, 1, 0, 4, 0, 2, 0, 0, 6, +}; +short yydgoto[] = { 2, + 3, 4, 5, 6, +}; +short yysindex[] = { -257, + 0, 0, 0, -257, 0, -252, 0, -257, -251, 0, +}; +short yyrindex[] = { 6, + 1, 0, 0, 3, 0, 0, 0, -250, 0, 0, +}; +short yygindex[] = { 0, + -4, 0, 0, 0, +}; +#define YYTABLESIZE 261 +short yytable[] = { 7, + 5, 1, 3, 9, 8, 3, 10, 3, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 7, 5, 5, + 3, +}; +short yycheck[] = { 4, + 0, 259, 0, 8, 257, 0, 258, 258, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 257, 258, 259, + 258, +}; +#define YYFINAL 2 +#ifndef YYDEBUG +#define YYDEBUG 0 +#endif +#define YYMAXTOKEN 259 +#if YYDEBUG +char *yyname[] = { +"end-of-file",0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,"OPENBRACE","CLOSEBRACE","STRING", +}; +char *yyrule[] = { +"$accept : toplist", +"toplist : valuelist", +"valuelist : value valuelist", +"valuelist :", +"value : key_value_pair", +"value : STRING", +"key_value_pair : key OPENBRACE valuelist CLOSEBRACE", +"key : STRING", +}; +#endif +#ifndef YYSTYPE +typedef int YYSTYPE; +#endif +#define yyclearin (yychar=(-1)) +#define yyerrok (yyerrflag=0) +#ifndef YYSTACKSIZE +#ifdef YYMAXDEPTH +#define YYSTACKSIZE YYMAXDEPTH +#else +#define YYSTACKSIZE 300 +#endif +#endif +int yydebug; +int yynerrs; +int yyerrflag; +int yychar; +short *yyssp; +YYSTYPE *yyvsp; +YYSTYPE yyval; +YYSTYPE yylval; +#define yystacksize YYSTACKSIZE +short yyss[YYSTACKSIZE]; +YYSTYPE yyvs[YYSTACKSIZE]; +#line 118 "installparse.y" +/*----------------------- Program Section --------------------------------*/ + +/*************************************************************************/ +void +Pk11Install_yyerror(char *message) +{ + char *tmp; + if(Pk11Install_yyerrstr) { + tmp=PR_smprintf("%sline %d: %s\n", Pk11Install_yyerrstr, + Pk11Install_yylinenum, message); + PR_smprintf_free(Pk11Install_yyerrstr); + } else { + tmp = PR_smprintf("line %d: %s\n", Pk11Install_yylinenum, message); + } + Pk11Install_yyerrstr=tmp; +} +#line 191 "ytab.c" +#define YYABORT goto yyabort +#define YYACCEPT goto yyaccept +#define YYERROR goto yyerrlab +int +yyparse() +{ + register int yym, yyn, yystate; +#if YYDEBUG + register char *yys; + extern char *getenv(); + + if (yys = getenv("YYDEBUG")) + { + yyn = *yys; + if (yyn >= '0' && yyn <= '9') + yydebug = yyn - '0'; + } +#endif + + yynerrs = 0; + yyerrflag = 0; + yychar = (-1); + + yyssp = yyss; + yyvsp = yyvs; + *yyssp = yystate = 0; + +yyloop: + if (yyn = yydefred[yystate]) goto yyreduce; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("yydebug: state %d, reading %d (%s)\n", yystate, + yychar, yys); + } +#endif + } + if ((yyn = yysindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { +#if YYDEBUG + if (yydebug) + printf("yydebug: state %d, shifting to state %d\n", + yystate, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + yychar = (-1); + if (yyerrflag > 0) --yyerrflag; + goto yyloop; + } + if ((yyn = yyrindex[yystate]) && (yyn += yychar) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yychar) + { + yyn = yytable[yyn]; + goto yyreduce; + } + if (yyerrflag) goto yyinrecovery; +#ifdef lint + goto yynewerror; +#endif +yynewerror: + yyerror("syntax error"); +#ifdef lint + goto yyerrlab; +#endif +yyerrlab: + ++yynerrs; +yyinrecovery: + if (yyerrflag < 3) + { + yyerrflag = 3; + for (;;) + { + if ((yyn = yysindex[*yyssp]) && (yyn += YYERRCODE) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == YYERRCODE) + { +#if YYDEBUG + if (yydebug) + printf("yydebug: state %d, error recovery shifting\ + to state %d\n", *yyssp, yytable[yyn]); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate = yytable[yyn]; + *++yyvsp = yylval; + goto yyloop; + } + else + { +#if YYDEBUG + if (yydebug) + printf("yydebug: error recovery discarding state %d\n", + *yyssp); +#endif + if (yyssp <= yyss) goto yyabort; + --yyssp; + --yyvsp; + } + } + } + else + { + if (yychar == 0) goto yyabort; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("yydebug: state %d, error recovery discards token %d (%s)\n", + yystate, yychar, yys); + } +#endif + yychar = (-1); + goto yyloop; + } +yyreduce: +#if YYDEBUG + if (yydebug) + printf("yydebug: state %d, reducing by rule %d (%s)\n", + yystate, yyn, yyrule[yyn]); +#endif + yym = yylen[yyn]; + yyval = yyvsp[1-yym]; + switch (yyn) + { +case 1: +#line 84 "installparse.y" +{ + Pk11Install_valueList = yyvsp[0].list; +} +break; +case 2: +#line 89 "installparse.y" +{ + Pk11Install_ValueList_AddItem(yyvsp[0].list,yyvsp[-1].value); + yyval .list = yyvsp[0].list; +} +break; +case 3: +#line 94 "installparse.y" +{ + yyval .list = Pk11Install_ValueList_new(); +} +break; +case 4: +#line 99 "installparse.y" +{ + yyval .value= Pk11Install_Value_new(PAIR_VALUE,yyvsp[0]); +} +break; +case 5: +#line 103 "installparse.y" +{ + yyval .value= Pk11Install_Value_new(STRING_VALUE, yyvsp[0]); +} +break; +case 6: +#line 108 "installparse.y" +{ + yyval .pair = Pk11Install_Pair_new(yyvsp[-3].string,yyvsp[-1].list); +} +break; +case 7: +#line 113 "installparse.y" +{ + yyval .string = yyvsp[0].string; +} +break; +#line 374 "ytab.c" + } + yyssp -= yym; + yystate = *yyssp; + yyvsp -= yym; + yym = yylhs[yyn]; + if (yystate == 0 && yym == 0) + { +#ifdef YYDEBUG + if (yydebug) + printf("yydebug: after reduction, shifting from state 0 to\ + state %d\n", YYFINAL); +#endif + yystate = YYFINAL; + *++yyssp = YYFINAL; + *++yyvsp = yyval; + if (yychar < 0) + { + if ((yychar = yylex()) < 0) yychar = 0; +#if YYDEBUG + if (yydebug) + { + yys = 0; + if (yychar <= YYMAXTOKEN) yys = yyname[yychar]; + if (!yys) yys = "illegal-symbol"; + printf("yydebug: state %d, reading %d (%s)\n", + YYFINAL, yychar, yys); + } +#endif + } + if (yychar == 0) goto yyaccept; + goto yyloop; + } + if ((yyn = yygindex[yym]) && (yyn += yystate) >= 0 && + yyn <= YYTABLESIZE && yycheck[yyn] == yystate) + yystate = yytable[yyn]; + else + yystate = yydgoto[yym]; +#ifdef YYDEBUG + if (yydebug) + printf("yydebug: after reduction, shifting from state %d \ +to state %d\n", *yyssp, yystate); +#endif + if (yyssp >= yyss + yystacksize - 1) + { + goto yyoverflow; + } + *++yyssp = yystate; + *++yyvsp = yyval; + goto yyloop; +yyoverflow: + yyerror("yacc stack overflow"); +yyabort: + return (1); +yyaccept: + return (0); +} diff --git a/security/nss/cmd/modutil/installparse.h b/security/nss/cmd/modutil/installparse.h new file mode 100644 index 000000000..75686d4fd --- /dev/null +++ b/security/nss/cmd/modutil/installparse.h @@ -0,0 +1,3 @@ +#define OPENBRACE 257 +#define CLOSEBRACE 258 +#define STRING 259 diff --git a/security/nss/cmd/modutil/installparse.l b/security/nss/cmd/modutil/installparse.l new file mode 100644 index 000000000..6befe16cb --- /dev/null +++ b/security/nss/cmd/modutil/installparse.l @@ -0,0 +1,166 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + + +/* lex file for analyzing PKCS #11 Module installation instructions */ + +/*----------------------------- Definitions ---------------------------*/ +%{ +#include <string.h> + +#include "install-ds.h" /* defines tokens and data structures */ +#include "installparse.h" /* produced by yacc -d */ +#include <prprf.h> +static char *putSimpleString(char*); /* return copy of string */ +static char *putComplexString(char*); /* strip out quotes, deal with */ + /* escaped characters */ + +void Pk11Install_yyerror(char *); + +/* Overrides to use NSPR */ +#define malloc PR_Malloc +#define realloc PR_Realloc +#define free PR_Free + +int Pk11Install_yylinenum=1; +static char *err; + +#define YY_NEVER_INTERACTIVE 1 +#define yyunput Pkcs11Install_yyunput + +/* This is the default YY_INPUT modified for NSPR */ +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) { \ + char c; \ + int n; \ + for ( n = 0; n < max_size && \ + PR_Read(Pk11Install_FD, &c, 1)==1 && c != '\n'; ++n ) { \ + buf[n] = c; \ + } \ + if ( c == '\n' ) { \ + buf[n++] = c; \ + } \ + result = n; \ + } else { \ + result = PR_Read(Pk11Install_FD, buf, max_size); \ + } + +%} + +/*** Regular expression definitions ***/ +/* simple_string has no whitespace, quotes, or braces */ +simple_string [^ \t\r\n\""{""}"]+ + +/* complex_string is enclosed in quotes. Inside the quotes, quotes and + backslashes must be backslash-escaped. No newlines or carriage returns + are allowed inside the quotes. Otherwise, anything goes. */ +complex_string \"([^\"\\\r\n]|(\\\")|(\\\\))+\" + +/* Standard whitespace */ +whitespace [ \t\r]+ + +other . + +/*---------------------------- Actions --------------------------------*/ +%% + +"{" return OPENBRACE; +"}" return CLOSEBRACE; +{simple_string} {Pk11Install_yylval.string = + putSimpleString(Pk11Install_yytext); + return STRING;} +{complex_string} {Pk11Install_yylval.string = + putComplexString(Pk11Install_yytext); + return STRING;} + +"\n" Pk11Install_yylinenum++; + +{whitespace} ; + +{other} {err = PR_smprintf("Invalid lexeme: %s",Pk11Install_yytext); + Pk11Install_yyerror(err); + PR_smprintf_free(err); + return 1; + } + +%% +/*------------------------ Program Section ----------------------------*/ + +PRFileDesc *Pk11Install_FD=NULL; + +/*************************************************************************/ +/* dummy function required by lex */ +int Pk11Install_yywrap(void) { return 1;} + +/*************************************************************************/ +/* Return a copy of the given string */ +static char* +putSimpleString(char *str) +{ + char *tmp = (char*) PR_Malloc(strlen(str)+1); + strcpy(tmp, str); + return tmp; +} + +/*************************************************************************/ +/* Strip out quotes, replace escaped characters with what they stand for. + This function assumes that what is passed in is actually a complex + string, so error checking is lax. */ +static char* +putComplexString(char *str) +{ + int size, i,j; + char *tmp; + + if(!str) { + return NULL; + } + size = strlen(str); + + /* Allocate the new space. This string will actually be too big, + since quotes and backslashes will be stripped out. But that's ok. */ + tmp = (char*) PR_Malloc(size+1); + + /* Copy it over */ + for(i=0, j=0; i < size; i++) { + if(str[i]=='\"') { + continue; /* skip un-escaped quotes */ + } else if(str[i]=='\\') { + ++i; /* escaped character. skip the backslash */ + } + tmp[j++] = str[i]; + } + tmp[j] = '\0'; + + return tmp; +} diff --git a/security/nss/cmd/modutil/installparse.y b/security/nss/cmd/modutil/installparse.y new file mode 100644 index 000000000..6a32e25ab --- /dev/null +++ b/security/nss/cmd/modutil/installparse.y @@ -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. + */ + +/* yacc file for parsing PKCS #11 module installation instructions */ +/*------------------------ Definition Section ---------------------------*/ + +%{ +#define yyparse Pk11Install_yyparse +#define yylex Pk11Install_yylex +#define yyerror Pk11Install_yyerror +#define yychar Pk11Install_yychar +#define yyval Pk11Install_yyval +#define yylval Pk11Install_yylval +#define yydebug Pk11Install_yydebug +#define yynerrs Pk11Install_yynerrs +#define yyerrflag Pk11Install_yyerrflag +#define yyss Pk11Install_yyss +#define yyssp Pk11Install_yyssp +#define yyvs Pk11Install_yyvs +#define yyvsp Pk11Install_yyvsp +#define yylhs Pk11Install_yylhs +#define yylen Pk11Install_yylen +#define yydefred Pk11Install_yydefred +#define yydgoto Pk11Install_yydgoto +#define yysindex Pk11Install_yysindex +#define yyrindex Pk11Install_yyrindex +#define yygindex Pk11Install_yygindex +#define yytable Pk11Install_yytable +#define yycheck Pk11Install_yycheck +#define yyname Pk11Install_yyname +#define yyrule Pk11Install_yyrule + +/* C Stuff */ +#include "install-ds.h" +#include <prprf.h> + +#define YYSTYPE Pk11Install_Pointer +extern char *Pk11Install_yytext; +char *Pk11Install_yyerrstr=NULL; + +%} + +/* Tokens */ +%token OPENBRACE +%token CLOSEBRACE +%token STRING +%start toplist + +%% + +/*--------------------------- Productions -------------------------------*/ + +toplist : valuelist +{ + Pk11Install_valueList = $1.list; +} + +valuelist : value valuelist +{ + Pk11Install_ValueList_AddItem($2.list,$1.value); + $$.list = $2.list; +} +| +{ + $$.list = Pk11Install_ValueList_new(); +}; + +value : key_value_pair +{ + $$.value= Pk11Install_Value_new(PAIR_VALUE,$1); +} +| STRING +{ + $$.value= Pk11Install_Value_new(STRING_VALUE, $1); +}; + +key_value_pair : key OPENBRACE valuelist CLOSEBRACE +{ + $$.pair = Pk11Install_Pair_new($1.string,$3.list); +}; + +key : STRING +{ + $$.string = $1.string; +}; + +%% +/*----------------------- Program Section --------------------------------*/ + +/*************************************************************************/ +void +Pk11Install_yyerror(char *message) +{ + char *tmp; + if(Pk11Install_yyerrstr) { + tmp=PR_smprintf("%sline %d: %s\n", Pk11Install_yyerrstr, + Pk11Install_yylinenum, message); + PR_smprintf_free(Pk11Install_yyerrstr); + } else { + tmp = PR_smprintf("line %d: %s\n", Pk11Install_yylinenum, message); + } + Pk11Install_yyerrstr=tmp; +} diff --git a/security/nss/cmd/modutil/instsec.c b/security/nss/cmd/modutil/instsec.c new file mode 100644 index 000000000..e6eaa384b --- /dev/null +++ b/security/nss/cmd/modutil/instsec.c @@ -0,0 +1,178 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 <plarena.h> +#include <prio.h> +#include <prprf.h> +#include <seccomon.h> +#include <secmod.h> +#include <jar.h> +#include <secutil.h> + +/* These are installation functions that make calls to the security library. + * We don't want to include security include files in the C++ code too much. + */ + +static char* PR_fgets(char *buf, int size, PRFileDesc *file); + +/*************************************************************************** + * + * P k 1 1 I n s t a l l _ A d d N e w M o d u l e + */ +int +Pk11Install_AddNewModule(char* moduleName, char* dllPath, + unsigned long defaultMechanismFlags, + unsigned long cipherEnableFlags) +{ + return (SECMOD_AddNewModule(moduleName, dllPath, + SECMOD_PubMechFlagstoInternal(defaultMechanismFlags), + SECMOD_PubCipherFlagstoInternal(cipherEnableFlags)) + == SECSuccess) ? 0 : -1; +} + +/************************************************************************* + * + * P k 1 1 I n s t a l l _ U s e r V e r i f y J a r + * + * Gives the user feedback on the signatures of a JAR files, asks them + * whether they actually want to continue. + * Assumes the jar structure has already been created and is valid. + * Returns 0 if the user wants to continue the installation, nonzero + * if the user wishes to abort. + */ +short +Pk11Install_UserVerifyJar(JAR *jar, PRFileDesc *out, PRBool query) +{ + JAR_Context *ctx; + JAR_Cert *fing; + JAR_Item *item; + char stdinbuf[80]; + int count=0; + + CERTCertificate *cert, *prev=NULL; + + PR_fprintf(out, "\nThis installation JAR file was signed by:\n"); + + ctx = JAR_find(jar, NULL, jarTypeSign); + + while(JAR_find_next(ctx, &item) >= 0 ) { + fing = (JAR_Cert*) item->data; + cert = fing->cert; + if(cert==prev) { + continue; + } + + count++; + PR_fprintf(out, "----------------------------------------------\n"); + if(cert) { + if(cert->nickname) { + PR_fprintf(out, "**NICKNAME**\n%s\n", cert->nickname); + } + if(cert->subjectName) { + PR_fprintf(out, "**SUBJECT NAME**\n%s\n", cert->subjectName); } + if(cert->issuerName) { + PR_fprintf(out, "**ISSUER NAME**\n%s\n", cert->issuerName); + } + } else { + PR_fprintf(out, "No matching certificate could be found.\n"); + } + PR_fprintf(out, "----------------------------------------------\n\n"); + + prev=cert; + } + + JAR_find_end(ctx); + + if(count==0) { + PR_fprintf(out, "No signatures found: JAR FILE IS UNSIGNED.\n"); + } + + if(query) { + PR_fprintf(out, +"Do you wish to continue this installation? (y/n) "); + + if(PR_fgets(stdinbuf, 80, PR_STDIN) != NULL) { + char *response; + + if( (response=strtok(stdinbuf, " \t\n\r")) ) { + if( !PL_strcasecmp(response, "y") || + !PL_strcasecmp(response, "yes") ) { + return 0; + } + } + } + } + + return 1; +} + +/************************************************************************** + * + * P R _ f g e t s + * + * fgets implemented with NSPR. + */ +static char* +PR_fgets(char *buf, int size, PRFileDesc *file) +{ + int i; + int status; + char c; + + i=0; + while(i < size-1) { + status = PR_Read(file, (void*) &c, 1); + if(status==-1) { + return NULL; + } else if(status==0) { + break; + } + buf[i++] = c; + if(c=='\n') { + break; + } + } + buf[i]='\0'; + + return buf; +} + +/************************************************************************** + * + * m y S E C U _ E r r o r S t r i n g + * + */ +const char* mySECU_ErrorString(int16 errnum) +{ + return SECU_Strerror(errnum); +} diff --git a/security/nss/cmd/modutil/lex.Pk11Install_yy.c b/security/nss/cmd/modutil/lex.Pk11Install_yy.c new file mode 100644 index 000000000..3943503db --- /dev/null +++ b/security/nss/cmd/modutil/lex.Pk11Install_yy.c @@ -0,0 +1,1691 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 yy_create_buffer Pk11Install_yy_create_buffer +#define yy_delete_buffer Pk11Install_yy_delete_buffer +#define yy_scan_buffer Pk11Install_yy_scan_buffer +#define yy_scan_string Pk11Install_yy_scan_string +#define yy_scan_bytes Pk11Install_yy_scan_bytes +#define yy_flex_debug Pk11Install_yy_flex_debug +#define yy_init_buffer Pk11Install_yy_init_buffer +#define yy_flush_buffer Pk11Install_yy_flush_buffer +#define yy_load_buffer_state Pk11Install_yy_load_buffer_state +#define yy_switch_to_buffer Pk11Install_yy_switch_to_buffer +#define yyin Pk11Install_yyin +#define yyleng Pk11Install_yyleng +#define yylex Pk11Install_yylex +#define yyout Pk11Install_yyout +#define yyrestart Pk11Install_yyrestart +#define yytext Pk11Install_yytext +#define yywrap Pk11Install_yywrap + +#line 20 "lex.Pk11Install_yy.c" +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header$ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include <stdio.h> + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include <stdlib.h> +//#include <unistd.h> + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include <io.h> +#include <stdlib.h> +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +extern int yyleng; +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + *yy_cp = yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int yy_size_t; + + +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE yy_current_buffer = 0; + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart YY_PROTO(( FILE *input_file )); + +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) + +YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); +YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); +YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + +typedef unsigned char YY_CHAR; +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +typedef int yy_state_type; +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 8 +#define YY_END_OF_BUFFER 9 +static yyconst short int yy_accept[16] = + { 0, + 0, 0, 9, 3, 6, 5, 7, 1, 2, 3, + 6, 0, 0, 4, 0 + } ; + +static yyconst int yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 5, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 6, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 7, 1, 8, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst int yy_meta[9] = + { 0, + 1, 2, 3, 4, 3, 1, 5, 5 + } ; + +static yyconst short int yy_base[19] = + { 0, + 0, 0, 19, 0, 0, 21, 12, 21, 21, 0, + 0, 4, 6, 21, 21, 13, 11, 15 + } ; + +static yyconst short int yy_def[19] = + { 0, + 15, 1, 15, 16, 17, 15, 18, 15, 15, 16, + 17, 18, 15, 15, 0, 15, 15, 15 + } ; + +static yyconst short int yy_nxt[30] = + { 0, + 4, 5, 6, 5, 7, 4, 8, 9, 14, 13, + 12, 12, 11, 10, 11, 12, 12, 13, 15, 12, + 3, 15, 15, 15, 15, 15, 15, 15, 15 + } ; + +static yyconst short int yy_chk[30] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 12, 12, + 13, 13, 17, 16, 17, 18, 18, 7, 3, 18, + 15, 15, 15, 15, 15, 15, 15, 15, 15 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "installparse.l" +#define INITIAL 0 +/* lex file for analyzing PKCS #11 Module installation instructions */ +/*----------------------------- Definitions ---------------------------*/ +#line 5 "installparse.l" +#include <string.h> + +#include "install-ds.h" /* defines tokens and data structures */ +#include "installparse.h" /* produced by yacc -d */ +#include <prprf.h> +static char *putSimpleString(char*); /* return copy of string */ +static char *putComplexString(char*); /* strip out quotes, deal with */ + /* escaped characters */ + +void Pk11Install_yyerror(char *); + +/* Overrides to use NSPR */ +#define malloc PR_Malloc +#define realloc PR_Realloc +#define free PR_Free + +int Pk11Install_yylinenum=1; +static char *err; + +#define YY_NEVER_INTERACTIVE 1 +#define yyunput Pkcs11Install_yyunput + +/* This is the default YY_INPUT modified for NSPR */ +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) { \ + char c; \ + int n; \ + for ( n = 0; n < max_size && \ + PR_Read(Pk11Install_FD, &c, 1)==1 && c != '\n'; ++n ) { \ + buf[n] = c; \ + } \ + if ( c == '\n' ) { \ + buf[n++] = c; \ + } \ + result = n; \ + } else { \ + result = PR_Read(Pk11Install_FD, buf, max_size); \ + } + +/*** Regular expression definitions ***/ +/* simple_string has no whitespace, quotes, or braces */ +/* complex_string is enclosed in quotes. Inside the quotes, quotes and + backslashes must be backslash-escaped. Otherwise, anything goes. */ +/* Standard whitespace */ +/*---------------------------- Actions --------------------------------*/ +#line 437 "lex.Pk11Install_yy.cpp" + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include <stdlib.h> +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 60 "installparse.l" + + +#line 591 "lex.Pk11Install_yy.cpp" + + if ( yy_init ) + { + yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! yy_current_buffer ) + yy_current_buffer = + yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 16 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 21 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 62 "installparse.l" +return OPENBRACE; + YY_BREAK +case 2: +YY_RULE_SETUP +#line 63 "installparse.l" +return CLOSEBRACE; + YY_BREAK +case 3: +YY_RULE_SETUP +#line 64 "installparse.l" +{Pk11Install_yylval.string = + putSimpleString(Pk11Install_yytext); + return STRING;} + YY_BREAK +case 4: +YY_RULE_SETUP +#line 67 "installparse.l" +{Pk11Install_yylval.string = + putComplexString(Pk11Install_yytext); + return STRING;} + YY_BREAK +case 5: +YY_RULE_SETUP +#line 71 "installparse.l" +Pk11Install_yylinenum++; + YY_BREAK +case 6: +YY_RULE_SETUP +#line 73 "installparse.l" +; + YY_BREAK +case 7: +YY_RULE_SETUP +#line 75 "installparse.l" +{err = PR_smprintf("Invalid lexeme: %s",Pk11Install_yytext); + Pk11Install_yyerror(err); + PR_smprintf_free(err); + return 1; + } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 81 "installparse.l" +ECHO; + YY_BREAK +#line 722 "lex.Pk11Install_yy.cpp" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yy_n_chars = yy_current_buffer->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = + yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of yylex */ + + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + { + register char *dest = yy_current_buffer->yy_ch_buf; + register char *source = yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( yy_current_buffer->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_current_buffer->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = yy_current_buffer; + + int yy_c_buf_p_offset = + (int) (yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yy_flex_realloc( (void *) b->yy_ch_buf, + b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = yy_current_buffer->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + + return ret_val; + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +static yy_state_type yy_get_previous_state() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + + for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 16 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +yy_state_type yy_current_state; +#endif + { + register int yy_is_jam; + register char *yy_cp = yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 16 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 15); + + return yy_is_jam ? 0 : yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void yyunput( int c, register char *yy_bp ) +#else +static void yyunput( c, yy_bp ) +int c; +register char *yy_bp; +#endif + { + register char *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yy_n_chars + 2; + register char *dest = &yy_current_buffer->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + + yytext_ptr = yy_bp; + yy_hold_char = *yy_cp; + yy_c_buf_p = yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + { + int c; + + *yy_c_buf_p = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* This was really a NUL. */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yy_c_buf_p - yytext_ptr; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ + *yy_c_buf_p = '\0'; /* preserve yytext */ + yy_hold_char = *++yy_c_buf_p; + + + return c; + } + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + +#ifndef YY_ALWAYS_INTERACTIVE +#ifndef YY_NEVER_INTERACTIVE +extern int isatty YY_PROTO(( int )); +#endif +#endif + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->yy_is_interactive = 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == yy_current_buffer ) + yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) +#else +YY_BUFFER_STATE yy_scan_buffer( base, size ) +char *base; +yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) +#else +YY_BUFFER_STATE yy_scan_string( yy_str ) +yyconst char *yy_str; +#endif + { + int len; + for ( len = 0; yy_str[len]; ++len ) + ; + + return yy_scan_bytes( yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE yy_scan_bytes( bytes, len ) +yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void yy_push_state( int new_state ) +#else +static void yy_push_state( new_state ) +int new_state; +#endif + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void yy_fatal_error( yyconst char msg[] ) +#else +static void yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif +#line 81 "installparse.l" + +/*------------------------ Program Section ----------------------------*/ + +PRFileDesc *Pk11Install_FD=NULL; + +/*************************************************************************/ +/* dummy function required by lex */ +int Pk11Install_yywrap(void) { return 1;} + +/*************************************************************************/ +/* Return a copy of the given string */ +static char* +putSimpleString(char *str) +{ + char *tmp = (char*) PR_Malloc(strlen(str)+1); + strcpy(tmp, str); + return tmp; +} + +/*************************************************************************/ +/* Strip out quotes, replace escaped characters with what they stand for. + This function assumes that what is passed in is actually a complex + string, so error checking is lax. */ +static char* +putComplexString(char *str) +{ + int size, i,j; + char *tmp; + + if(!str) { + return NULL; + } + size = strlen(str); + + /* Allocate the new space. This string will actually be too big, + since quotes and backslashes will be stripped out. But that's ok. */ + tmp = (char*) PR_Malloc(size+1); + + /* Copy it over */ + for(i=0, j=0; i < size; i++) { + if(str[i]=='\"') { + continue; /* skip un-escaped quotes */ + } else if(str[i]=='\\') { + ++i; /* escaped character. skip the backslash */ + } + tmp[j++] = str[i]; + } + tmp[j] = '\0'; + + return tmp; +} diff --git a/security/nss/cmd/modutil/manifest.mn b/security/nss/cmd/modutil/manifest.mn new file mode 100644 index 000000000..b9ff7dc18 --- /dev/null +++ b/security/nss/cmd/modutil/manifest.mn @@ -0,0 +1,62 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +MODULE = sectools + +EXPORTS = + +CSRCS = modutil.c \ + pk11.c \ + instsec.c \ + install.c \ + installparse.c \ + install-ds.c \ + lex.Pk11Install_yy.c \ + $(NULL) + +CPPSRCS = + +PROGRAM = modutil + +REQUIRES = seccmd nss dbm + +DEFINES = -DNSPR20 + +# sigh +#INCLUDES += -I$(CORE_DEPTH)/nss/lib/pk11wrap + +# USE_STATIC_LIBS = 1 + +EXTRA_LIBS = $(JAR_LIBS) diff --git a/security/nss/cmd/modutil/modutil.c b/security/nss/cmd/modutil/modutil.c new file mode 100644 index 000000000..ba67ffa3c --- /dev/null +++ b/security/nss/cmd/modutil/modutil.c @@ -0,0 +1,999 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "modutil.h" +#include "install.h" +#include <plstr.h> +#include "secrng.h" +#include "certdb.h" /* for CERT_DB_FILE_VERSION */ +#include "nss.h" + +static void install_error(char *message); +static char* PR_fgets(char *buf, int size, PRFileDesc *file); +static char *progName; + + +/* This enum must be kept in sync with the commandNames list */ +typedef enum { + NO_COMMAND, + ADD_COMMAND, + CHANGEPW_COMMAND, + CREATE_COMMAND, + DEFAULT_COMMAND, + DELETE_COMMAND, + DISABLE_COMMAND, + ENABLE_COMMAND, + FIPS_COMMAND, + JAR_COMMAND, + LIST_COMMAND, + RAW_LIST_COMMAND, + RAW_ADD_COMMAND, + CHKFIPS_COMMAND, + UNDEFAULT_COMMAND +} Command; + +/* This list must be kept in sync with the Command enum */ +static char *commandNames[] = { + "(no command)", + "-add", + "-changepw", + "-create", + "-default", + "-delete", + "-disable", + "-enable", + "-fips", + "-jar", + "-list", + "-rawlist", + "-rawadd", + "-chkfips", + "-undefault" +}; + + +/* this enum must be kept in sync with the optionStrings list */ +typedef enum { + ADD_ARG=0, + RAW_ADD_ARG, + CHANGEPW_ARG, + CIPHERS_ARG, + CREATE_ARG, + DBDIR_ARG, + DBPREFIX_ARG, + DEFAULT_ARG, + DELETE_ARG, + DISABLE_ARG, + ENABLE_ARG, + FIPS_ARG, + FORCE_ARG, + JAR_ARG, + LIBFILE_ARG, + LIST_ARG, + RAW_LIST_ARG, + MECHANISMS_ARG, + NEWPWFILE_ARG, + PWFILE_ARG, + SLOT_ARG, + UNDEFAULT_ARG, + INSTALLDIR_ARG, + TEMPDIR_ARG, + SECMOD_ARG, + NOCERTDB_ARG, + STRING_ARG, + CHKFIPS_ARG, + + NUM_ARGS /* must be last */ +} Arg; + +/* This list must be kept in sync with the Arg enum */ +static char *optionStrings[] = { + "-add", + "-rawadd", + "-changepw", + "-ciphers", + "-create", + "-dbdir", + "-dbprefix", + "-default", + "-delete", + "-disable", + "-enable", + "-fips", + "-force", + "-jar", + "-libfile", + "-list", + "-rawlist", + "-mechanisms", + "-newpwfile", + "-pwfile", + "-slot", + "-undefault", + "-installdir", + "-tempdir", + "-secmod", + "-nocertdb", + "-string", + "-chkfips", +}; + +/* Increment i if doing so would have i still be less than j. If you + are able to do this, return 0. Otherwise return 1. */ +#define TRY_INC(i,j) ( ((i+1)<j) ? (++i, 0) : 1 ) + +/******************************************************************** + * + * file-wide variables obtained from the command line + */ +static Command command = NO_COMMAND; +static char* pwFile = NULL; +static char* newpwFile = NULL; +static char* moduleName = NULL; +static char* moduleSpec = NULL; +static char* slotName = NULL; +static char* secmodName = NULL; +static char* tokenName = NULL; +static char* libFile = NULL; +static char* dbdir = NULL; +static char* dbprefix = ""; +static char* secmodString = NULL; +static char* mechanisms = NULL; +static char* ciphers = NULL; +static char* fipsArg = NULL; +static char* jarFile = NULL; +static char* installDir = NULL; +static char* tempDir = NULL; +static short force = 0; +static PRBool nocertdb = PR_FALSE; + +/******************************************************************* + * + * p a r s e _ a r g s + */ +static Error +parse_args(int argc, char *argv[]) +{ + int i; + char *arg; + int optionType; + + /* Loop over all arguments */ + for(i=1; i < argc; i++) { + arg = argv[i]; + + /* Make sure this is an option and not some floating argument */ + if(arg[0] != '-') { + PR_fprintf(PR_STDERR, errStrings[UNEXPECTED_ARG_ERR], argv[i]); + return UNEXPECTED_ARG_ERR; + } + + /* Find which option this is */ + for(optionType=0; optionType < NUM_ARGS; optionType++) { + if(! strcmp(arg, optionStrings[optionType])) { + break; + } + } + + /* Deal with this specific option */ + switch(optionType) { + case NUM_ARGS: + default: + PR_fprintf(PR_STDERR, errStrings[UNKNOWN_OPTION_ERR], arg); + return UNKNOWN_OPTION_ERR; + break; + case ADD_ARG: + if(command != NO_COMMAND) { + PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg); + return MULTIPLE_COMMAND_ERR; + } + command = ADD_COMMAND; + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + moduleName = argv[i]; + break; + case CHANGEPW_ARG: + if(command != NO_COMMAND) { + PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg); + return MULTIPLE_COMMAND_ERR; + } + command = CHANGEPW_COMMAND; + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + tokenName = argv[i]; + break; + case CIPHERS_ARG: + if(ciphers != NULL) { + PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg); + return DUPLICATE_OPTION_ERR; + } + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + ciphers = argv[i]; + break; + case CREATE_ARG: + if(command != NO_COMMAND) { + PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg); + return MULTIPLE_COMMAND_ERR; + } + command = CREATE_COMMAND; + break; + case DBDIR_ARG: + if(dbdir != NULL) { + PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg); + return DUPLICATE_OPTION_ERR; + } + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + dbdir = argv[i]; + break; + case DBPREFIX_ARG: + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + dbprefix = argv[i]; + break; + case UNDEFAULT_ARG: + case DEFAULT_ARG: + if(command != NO_COMMAND) { + PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg); + return MULTIPLE_COMMAND_ERR; + } + if(optionType == DEFAULT_ARG) { + command = DEFAULT_COMMAND; + } else { + command = UNDEFAULT_COMMAND; + } + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + moduleName = argv[i]; + break; + case DELETE_ARG: + if(command != NO_COMMAND) { + PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg); + return MULTIPLE_COMMAND_ERR; + } + command = DELETE_COMMAND; + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + moduleName = argv[i]; + break; + case DISABLE_ARG: + if(command != NO_COMMAND) { + PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg); + return MULTIPLE_COMMAND_ERR; + } + command = DISABLE_COMMAND; + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + moduleName = argv[i]; + break; + case ENABLE_ARG: + if(command != NO_COMMAND) { + PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg); + return MULTIPLE_COMMAND_ERR; + } + command = ENABLE_COMMAND; + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + moduleName = argv[i]; + break; + case FIPS_ARG: + if(command != NO_COMMAND) { + PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg); + return MULTIPLE_COMMAND_ERR; + } + command = FIPS_COMMAND; + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + fipsArg = argv[i]; + break; + case CHKFIPS_ARG: + if(command != NO_COMMAND) { + PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg); + return MULTIPLE_COMMAND_ERR; + } + command = CHKFIPS_COMMAND; + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + fipsArg = argv[i]; + break; + case FORCE_ARG: + force = 1; + break; + case NOCERTDB_ARG: + nocertdb = PR_TRUE; + break; + case INSTALLDIR_ARG: + if(installDir != NULL) { + PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg); + return DUPLICATE_OPTION_ERR; + } + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + installDir = argv[i]; + break; + case TEMPDIR_ARG: + if(tempDir != NULL) { + PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg); + return DUPLICATE_OPTION_ERR; + } + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + tempDir = argv[i]; + break; + case JAR_ARG: + if(command != NO_COMMAND) { + PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg); + return MULTIPLE_COMMAND_ERR; + } + command = JAR_COMMAND; + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + jarFile = argv[i]; + break; + case LIBFILE_ARG: + if(libFile != NULL) { + PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg); + return DUPLICATE_OPTION_ERR; + } + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + libFile = argv[i]; + break; + case LIST_ARG: + if(command != NO_COMMAND) { + PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg); + return MULTIPLE_COMMAND_ERR; + } + command = LIST_COMMAND; + /* This option may or may not have an argument */ + if( (i+1 < argc) && (argv[i+1][0] != '-') ) { + moduleName = argv[++i]; + } + break; + case RAW_LIST_ARG: + if(command != NO_COMMAND) { + PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg); + return MULTIPLE_COMMAND_ERR; + } + command = RAW_LIST_COMMAND; + /* This option may or may not have an argument */ + if( (i+1 < argc) && (argv[i+1][0] != '-') ) { + moduleName = argv[++i]; + } + break; + case RAW_ADD_ARG: + if(command != NO_COMMAND) { + PR_fprintf(PR_STDERR, errStrings[MULTIPLE_COMMAND_ERR], arg); + return MULTIPLE_COMMAND_ERR; + } + command = RAW_ADD_COMMAND; + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + moduleSpec = argv[i]; + break; + case MECHANISMS_ARG: + if(mechanisms != NULL) { + PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg); + return DUPLICATE_OPTION_ERR; + } + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + mechanisms = argv[i]; + break; + case NEWPWFILE_ARG: + if(newpwFile != NULL) { + PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg); + return DUPLICATE_OPTION_ERR; + } + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + newpwFile = argv[i]; + break; + case PWFILE_ARG: + if(pwFile != NULL) { + PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg); + return DUPLICATE_OPTION_ERR; + } + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + pwFile = argv[i]; + break; + case SLOT_ARG: + if(slotName != NULL) { + PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg); + return DUPLICATE_OPTION_ERR; + } + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + slotName = argv[i]; + break; + case SECMOD_ARG: + if(secmodName != NULL) { + PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg); + return DUPLICATE_OPTION_ERR; + } + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + secmodName = argv[i]; + break; + case STRING_ARG: + if(secmodString != NULL) { + PR_fprintf(PR_STDERR, errStrings[DUPLICATE_OPTION_ERR], arg); + return DUPLICATE_OPTION_ERR; + } + if(TRY_INC(i, argc)) { + PR_fprintf(PR_STDERR, errStrings[OPTION_NEEDS_ARG_ERR], arg); + return OPTION_NEEDS_ARG_ERR; + } + secmodString = argv[i]; + break; + } + } + return SUCCESS; +} + +/************************************************************************ + * + * v e r i f y _ p a r a m s + */ +static Error +verify_params() +{ + switch(command) { + case ADD_COMMAND: + if(libFile == NULL) { + PR_fprintf(PR_STDERR, errStrings[MISSING_PARAM_ERR], + commandNames[ADD_COMMAND], optionStrings[LIBFILE_ARG]); + return MISSING_PARAM_ERR; + } + break; + case CHANGEPW_COMMAND: + break; + case CREATE_COMMAND: + break; + case DELETE_COMMAND: + break; + case DISABLE_COMMAND: + break; + case ENABLE_COMMAND: + break; + case FIPS_COMMAND: + case CHKFIPS_COMMAND: + if(PL_strcasecmp(fipsArg, "true") && + PL_strcasecmp(fipsArg, "false")) { + PR_fprintf(PR_STDERR, errStrings[INVALID_FIPS_ARG]); + return INVALID_FIPS_ARG; + } + break; + case JAR_COMMAND: + if(installDir == NULL) { + PR_fprintf(PR_STDERR, errStrings[MISSING_PARAM_ERR], + commandNames[JAR_COMMAND], optionStrings[INSTALLDIR_ARG]); + return MISSING_PARAM_ERR; + } + break; + case LIST_COMMAND: + case RAW_LIST_COMMAND: + break; + case RAW_ADD_COMMAND: + break; + case UNDEFAULT_COMMAND: + case DEFAULT_COMMAND: + if(mechanisms == NULL) { + PR_fprintf(PR_STDERR, errStrings[MISSING_PARAM_ERR], + commandNames[command], optionStrings[MECHANISMS_ARG]); + return MISSING_PARAM_ERR; + } + break; + default: + /* Ignore this here */ + break; + } + + return SUCCESS; +} + +/******************************************************************** + * + * i n i t _ c r y p t o + * + * Does crypto initialization that all commands will require. + * If -nocertdb option is specified, don't open key or cert db (we don't + * need them if we aren't going to be verifying signatures). This is + * because serverland doesn't always have cert and key database files + * available. + */ +static Error +init_crypto(PRBool create, PRBool readOnly) +{ + char *dir; +#ifdef notdef + char *moddbname=NULL, *keydbname, *certdbname; + PRBool free_moddbname = PR_FALSE; +#endif + Error retval; + SECStatus rv; + PRUint32 flags = 0; + + if (secmodName == NULL) { + secmodName = "secmod.db"; + } + + if(SECU_ConfigDirectory(dbdir)[0] == '\0') { + PR_fprintf(PR_STDERR, errStrings[NO_DBDIR_ERR]); + retval=NO_DBDIR_ERR; + goto loser; + } + dir = SECU_ConfigDirectory(NULL); + + /* Make sure db directory exists and is readable */ + if(PR_Access(dir, PR_ACCESS_EXISTS) != PR_SUCCESS) { + PR_fprintf(PR_STDERR, errStrings[DIR_DOESNT_EXIST_ERR], dir); + retval = DIR_DOESNT_EXIST_ERR; + goto loser; + } else if(PR_Access(dir, PR_ACCESS_READ_OK) != PR_SUCCESS) { + PR_fprintf(PR_STDERR, errStrings[DIR_NOT_READABLE_ERR], dir); + retval = DIR_NOT_READABLE_ERR; + goto loser; + } + + /* Check for the proper permissions on databases */ + if(create) { + /* Make sure dbs don't already exist, and the directory is + writeable */ +#ifdef notdef + if(PR_Access(moddbname, PR_ACCESS_EXISTS)==PR_SUCCESS) { + PR_fprintf(PR_STDERR, errStrings[FILE_ALREADY_EXISTS_ERR], + moddbname); + retval=FILE_ALREADY_EXISTS_ERR; + goto loser; + } else if(PR_Access(keydbname, PR_ACCESS_EXISTS)==PR_SUCCESS) { + PR_fprintf(PR_STDERR, errStrings[FILE_ALREADY_EXISTS_ERR], keydbname); + retval=FILE_ALREADY_EXISTS_ERR; + goto loser; + } else if(PR_Access(certdbname, PR_ACCESS_EXISTS)==PR_SUCCESS) { + PR_fprintf(PR_STDERR, errStrings[FILE_ALREADY_EXISTS_ERR],certdbname); + retval=FILE_ALREADY_EXISTS_ERR; + goto loser; + } else +#endif + if(PR_Access(dir, PR_ACCESS_WRITE_OK) != PR_SUCCESS) { + PR_fprintf(PR_STDERR, errStrings[DIR_NOT_WRITEABLE_ERR], dir); + retval=DIR_NOT_WRITEABLE_ERR; + goto loser; + } + } else { +#ifdef notdef + /* Make sure dbs are readable and writeable */ + if(PR_Access(moddbname, PR_ACCESS_READ_OK) != PR_SUCCESS) { +#ifndef XP_PC + /* in serverland, they always use secmod.db, even on UNIX. Try + this */ + moddbname = PR_smprintf("%s/secmod.db", dir); + free_moddbname = PR_TRUE; + if(PR_Access(moddbname, PR_ACCESS_READ_OK) != PR_SUCCESS) { +#endif + PR_fprintf(PR_STDERR, errStrings[FILE_NOT_READABLE_ERR], moddbname); + retval=FILE_NOT_READABLE_ERR; + goto loser; +#ifndef XP_PC + } +#endif + } + if(!nocertdb) { /* don't open cert and key db if -nocertdb */ + if(PR_Access(keydbname, PR_ACCESS_READ_OK) != PR_SUCCESS) { + PR_fprintf(PR_STDERR, errStrings[FILE_NOT_READABLE_ERR], + keydbname); + retval=FILE_NOT_READABLE_ERR; + goto loser; + } + if(PR_Access(certdbname, PR_ACCESS_READ_OK) != PR_SUCCESS) { + PR_fprintf(PR_STDERR, errStrings[FILE_NOT_READABLE_ERR], + certdbname); + retval=FILE_NOT_READABLE_ERR; + goto loser; + } + } +#endif + + /* Check for write access if we'll be making changes */ + if( !readOnly ) { +#ifdef notdef + if(PR_Access(moddbname, PR_ACCESS_WRITE_OK) != PR_SUCCESS) { + PR_fprintf(PR_STDERR, errStrings[FILE_NOT_WRITEABLE_ERR], + moddbname); + retval=FILE_NOT_WRITEABLE_ERR; + goto loser; + } + if(!nocertdb) { /* don't open key and cert db if -nocertdb */ + if(PR_Access(keydbname, PR_ACCESS_WRITE_OK) + != PR_SUCCESS) { + PR_fprintf(PR_STDERR, errStrings[FILE_NOT_WRITEABLE_ERR], + keydbname); + retval=FILE_NOT_WRITEABLE_ERR; + goto loser; + } + if(PR_Access(certdbname, PR_ACCESS_WRITE_OK) + != PR_SUCCESS) { + PR_fprintf(PR_STDERR, errStrings[FILE_NOT_WRITEABLE_ERR], + certdbname); + retval=FILE_NOT_WRITEABLE_ERR; + goto loser; + } + } +#endif + } + PR_fprintf(PR_STDOUT, msgStrings[USING_DBDIR_MSG], + SECU_ConfigDirectory(NULL)); + } + + /* Open/create key database */ + flags = 0; + if (readOnly) flags |= NSS_INIT_READONLY; + if (nocertdb) flags |= NSS_INIT_NOCERTDB; + rv = NSS_Initialize(SECU_ConfigDirectory(NULL), dbprefix, dbprefix, + secmodName, flags); + if (rv != SECSuccess) { + SECU_PrintPRandOSError(progName); + retval=NSS_INITIALIZE_FAILED_ERR; + goto loser; + } + + retval=SUCCESS; +loser: +#ifdef notdef + if(free_moddbname) { + PR_Free(moddbname); + } +#endif + return retval; +} + +/************************************************************************* + * + * u s a g e + */ +static void +usage() +{ + PR_fprintf(PR_STDOUT, +"\nNetscape Cryptographic Module Utility\n" +"Usage: modutil [command] [options]\n\n" +" COMMANDS\n" +"---------------------------------------------------------------------------\n" +"-add MODULE_NAME Add the named module to the module database\n" +" -libfile LIBRARY_FILE The name of the file (.so or .dll)\n" +" containing the implementation of PKCS #11\n" +" [-ciphers CIPHER_LIST] Enable the given ciphers on this module\n" +" [-mechanisms MECHANISM_LIST] Make the module a default provider of the\n" +" given mechanisms\n" +" [-string CONFIG_STRING] Pass a configuration string to this module\n" +"-changepw TOKEN Change the password on the named token\n" +" [-pwfile FILE] The old password is in this file\n" +" [-newpwfile FILE] The new password is in this file\n" +"-create Create a new set of security databases\n" +"-default MODULE Make the given module a default provider\n" +" -mechanisms MECHANISM_LIST of the given mechanisms\n" +" [-slot SLOT] limit change to only the given slot\n" +"-delete MODULE Remove the named module from the module\n" +" database\n" +"-disable MODULE Disable the named module\n" +" [-slot SLOT] Disable only the named slot on the module\n" +"-enable MODULE Enable the named module\n" +" [-slot SLOT] Enable only the named slot on the module\n" +"-fips [ true | false ] If true, enable FIPS mode. If false,\n" +" disable FIPS mode\n" +"-force Do not run interactively\n" +"-jar JARFILE Install a PKCS #11 module from the given\n" +" JAR file in the PKCS #11 JAR format\n" +" -installdir DIR Use DIR as the root directory of the\n" +" installation\n" +" [-tempdir DIR] Use DIR as the temporary installation\n" +" directory. If not specified, the current\n" +" directory is used\n" +"-list [MODULE] Lists information about the specified module\n" +" or about all modules if none is specified\n" +"-chkfips [ true | false ] If true, verify FIPS mode. If false,\n" +" verify not FIPS mode\n" +"-undefault MODULE The given module is NOT a default provider\n" +" -mechanisms MECHANISM_LIST of the listed mechanisms\n" +" [-slot SLOT] limit change to only the given slot\n" +"---------------------------------------------------------------------------\n" +"\n" +" OPTIONS\n" +"---------------------------------------------------------------------------\n" +"-dbdir DIR Directory DIR contains the security databases\n" +"-dbprefix prefix Prefix for the security databases\n" +"-nocertdb Do not load certificate or key databases. No\n" +" verification will be performed on JAR files.\n" +"-secmod secmodName Name of the security modules file\n" +"---------------------------------------------------------------------------\n" +"\n" +"Mechanism lists are colon-separated. The following mechanisms are recognized:\n" +"RSA, DSA, RC2, RC4, RC5, DES, DH, FORTEZZA, SHA1, MD5, MD2, SSL, TLS, RANDOM,\n" +" FRIENDLY\n" +"\n" +"Cipher lists are colon-separated. The following ciphers are recognized:\n" +"FORTEZZA\n" +"\nQuestions or bug reports should be sent to modutil-support@netscape.com.\n" +); + +} + +/************************************************************************* + * + * m a i n + */ +int +main(int argc, char *argv[]) +{ + int errcode = SUCCESS; + PRBool createdb, readOnly; +#define STDINBUF_SIZE 80 + char stdinbuf[STDINBUF_SIZE]; + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + + PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 0); + + if(parse_args(argc, argv) != SUCCESS) { + usage(); + errcode = INVALID_USAGE_ERR; + goto loser; + } + + if(verify_params() != SUCCESS) { + usage(); + errcode = INVALID_USAGE_ERR; + goto loser; + } + + if(command==NO_COMMAND) { + PR_fprintf(PR_STDERR, errStrings[NO_COMMAND_ERR]); + usage(); + errcode = INVALID_USAGE_ERR; + goto loser; + } + + if ((command == RAW_LIST_COMMAND) || (command == RAW_ADD_COMMAND)) { + if(!moduleName) { + char *readOnlyStr, *noCertDBStr, *sep; + if (!secmodName) secmodName="secmod.db"; + if (!dbprefix) dbprefix = ""; + sep = ((command == RAW_LIST_COMMAND) && nocertdb) ? "," : " "; + readOnlyStr = (command == RAW_LIST_COMMAND) ? "readOnly" : "" ; + noCertDBStr = nocertdb ? "noCertDB" : ""; + SECU_ConfigDirectory(dbdir); + + moduleName=PR_smprintf("name=\"NSS default Module DB\" parameters=\"configdir=%s certPrefix=%s keyPrefix=%s secmod=%s flags=%s%s%s\" NSS=\"flags=internal,moduleDB,moduleDBOnly,critical\"", + SECU_ConfigDirectory(NULL),dbprefix, dbprefix, + secmodName, readOnlyStr,sep, noCertDBStr); + } + if (command == RAW_LIST_COMMAND) { + errcode = RawListModule(moduleName); + } else { + PORT_Assert(moduleSpec); + errcode = RawAddModule(moduleName,moduleSpec); + } + goto loser; + } + + /* Set up crypto stuff */ + createdb = command==CREATE_COMMAND; + readOnly = ((command==LIST_COMMAND) || (command==CHKFIPS_COMMAND)); + + /* Make sure browser is not running if we're writing to a database */ + /* Do this before initializing crypto */ + if(!readOnly && !force) { + char *response; + + PR_fprintf(PR_STDOUT, msgStrings[BROWSER_RUNNING_MSG]); + if( ! PR_fgets(stdinbuf, STDINBUF_SIZE, PR_STDIN)) { + PR_fprintf(PR_STDERR, errStrings[STDIN_READ_ERR]); + errcode = STDIN_READ_ERR; + goto loser; + } + if( (response=strtok(stdinbuf, " \r\n\t")) ) { + if(!PL_strcasecmp(response, "q")) { + PR_fprintf(PR_STDOUT, msgStrings[ABORTING_MSG]); + errcode = SUCCESS; + goto loser; + } + } + PR_fprintf(PR_STDOUT, "\n"); + } + + errcode = init_crypto(createdb, readOnly); + if( errcode != SUCCESS) { + goto loser; + } + + + /* Execute the command */ + switch(command) { + case ADD_COMMAND: + errcode = AddModule(moduleName, libFile, ciphers, mechanisms, secmodString); + break; + case CHANGEPW_COMMAND: + errcode = ChangePW(tokenName, pwFile, newpwFile); + break; + case CREATE_COMMAND: + /* The work was already done in init_crypto() */ + break; + case DEFAULT_COMMAND: + errcode = SetDefaultModule(moduleName, slotName, mechanisms); + break; + case DELETE_COMMAND: + errcode = DeleteModule(moduleName); + break; + case DISABLE_COMMAND: + errcode = EnableModule(moduleName, slotName, PR_FALSE); + break; + case ENABLE_COMMAND: + errcode = EnableModule(moduleName, slotName, PR_TRUE); + break; + case FIPS_COMMAND: + errcode = FipsMode(fipsArg); + break; + case CHKFIPS_COMMAND: + errcode = ChkFipsMode(fipsArg); + break; + case JAR_COMMAND: + Pk11Install_SetErrorHandler(install_error); + errcode = Pk11Install_DoInstall(jarFile, installDir, tempDir, + PR_STDOUT, force, nocertdb); + break; + case LIST_COMMAND: + if(moduleName) { + errcode = ListModule(moduleName); + } else { + errcode = ListModules(); + } + break; + case UNDEFAULT_COMMAND: + errcode = UnsetDefaultModule(moduleName, slotName, mechanisms); + break; + default: + PR_fprintf(PR_STDERR, "This command is not supported yet.\n"); + errcode = INVALID_USAGE_ERR; + break; + } + + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + +loser: + PR_Cleanup(); + return errcode; +} + +/************************************************************************ + * + * i n s t a l l _ e r r o r + * + * Callback function to handle errors in PK11 JAR file installation. + */ +static void +install_error(char *message) +{ + PR_fprintf(PR_STDERR, "Install error: %s\n", message); +} + +/************************************************************************* + * + * o u t _ o f _ m e m o r y + */ +void +out_of_memory(void) +{ + PR_fprintf(PR_STDERR, errStrings[OUT_OF_MEM_ERR]); + exit(OUT_OF_MEM_ERR); +} + + +/************************************************************************** + * + * P R _ f g e t s + * + * fgets implemented with NSPR. + */ +static char* +PR_fgets(char *buf, int size, PRFileDesc *file) +{ + int i; + int status; + char c; + + i=0; + while(i < size-1) { + status = PR_Read(file, (void*) &c, 1); + if(status==-1) { + return NULL; + } else if(status==0) { + break; + } + buf[i++] = c; + if(c=='\n') { + break; + } + } + buf[i]='\0'; + + return buf; +} diff --git a/security/nss/cmd/modutil/modutil.h b/security/nss/cmd/modutil/modutil.h new file mode 100644 index 000000000..e6a0eeb13 --- /dev/null +++ b/security/nss/cmd/modutil/modutil.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. + */ + +#ifndef MODUTIL_H +#define MODUTIL_H + +#include <stdio.h> +#include <prio.h> +#include <prprf.h> +#include <prinit.h> +#include <prmem.h> +#include <plarena.h> +#include <string.h> +#include <seccomon.h> +#include <secmod.h> +#include <secutil.h> + +#include <prlock.h> + +#include "error.h" + +Error FipsMode(char *arg); +Error ChkFipsMode(char *arg); +Error AddModule(char *moduleName, char *libFile, char *ciphers, + char *mechanisms, char* modparms); +Error DeleteModule(char *moduleName); +Error ListModule(char *moduleName); +Error ListModules(); +Error ChangePW(char *tokenName, char *pwFile, char *newpwFile); +Error EnableModule(char *moduleName, char *slotName, PRBool enable); +Error RawAddModule(char *dbmodulespec, char *modulespec); +Error RawListModule(char *modulespec); +Error SetDefaultModule(char *moduleName, char *slotName, char *mechanisms); +Error UnsetDefaultModule(char *moduleName, char *slotName, char *mechanisms); +void out_of_memory(void); + +#endif /*MODUTIL_H*/ diff --git a/security/nss/cmd/modutil/pk11.c b/security/nss/cmd/modutil/pk11.c new file mode 100644 index 000000000..5a4041169 --- /dev/null +++ b/security/nss/cmd/modutil/pk11.c @@ -0,0 +1,919 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "modutil.h" +/* #include "secmodti.h" */ +#include "pk11func.h" + +static PK11DefaultArrayEntry *pk11_DefaultArray = NULL; +static int pk11_DefaultArraySize = 0; + +/************************************************************************* + * + * F i p s M o d e + * If arg=="true", enable FIPS mode on the internal module. If arg=="false", + * disable FIPS mode on the internal module. + */ +Error +FipsMode(char *arg) +{ + char *internal_name; + + if(!PORT_Strcasecmp(arg, "true")) { + if(!PK11_IsFIPS()) { + internal_name = PR_smprintf("%s", + SECMOD_GetInternalModule()->commonName); + if(SECMOD_DeleteInternalModule(internal_name) != SECSuccess) { + PR_fprintf(PR_STDERR, "%s\n", SECU_Strerror(PORT_GetError())); + PR_smprintf_free(internal_name); + PR_fprintf(PR_STDERR, errStrings[FIPS_SWITCH_FAILED_ERR]); + return FIPS_SWITCH_FAILED_ERR; + } + PR_smprintf_free(internal_name); + if (!PK11_IsFIPS()) { + PR_fprintf(PR_STDERR, errStrings[FIPS_SWITCH_FAILED_ERR]); + return FIPS_SWITCH_FAILED_ERR; + } + PR_fprintf(PR_STDOUT, msgStrings[FIPS_ENABLED_MSG]); + } else { + PR_fprintf(PR_STDERR, errStrings[FIPS_ALREADY_ON_ERR]); + return FIPS_ALREADY_ON_ERR; + } + } else if(!PORT_Strcasecmp(arg, "false")) { + if(PK11_IsFIPS()) { + internal_name = PR_smprintf("%s", + SECMOD_GetInternalModule()->commonName); + if(SECMOD_DeleteInternalModule(internal_name) != SECSuccess) { + PR_fprintf(PR_STDERR, "%s\n", SECU_Strerror(PORT_GetError())); + PR_smprintf_free(internal_name); + PR_fprintf(PR_STDERR, errStrings[FIPS_SWITCH_FAILED_ERR]); + return FIPS_SWITCH_FAILED_ERR; + } + PR_smprintf_free(internal_name); + if (PK11_IsFIPS()) { + PR_fprintf(PR_STDERR, errStrings[FIPS_SWITCH_FAILED_ERR]); + return FIPS_SWITCH_FAILED_ERR; + } + PR_fprintf(PR_STDOUT, msgStrings[FIPS_DISABLED_MSG]); + } else { + PR_fprintf(PR_STDERR, errStrings[FIPS_ALREADY_OFF_ERR]); + return FIPS_ALREADY_OFF_ERR; + } + } else { + PR_fprintf(PR_STDERR, errStrings[INVALID_FIPS_ARG]); + return INVALID_FIPS_ARG; + } + + return SUCCESS; +} + +/************************************************************************* + * + * C h k F i p s M o d e + * If arg=="true", verify FIPS mode is enabled on the internal module. + * If arg=="false", verify FIPS mode is disabled on the internal module. + */ +Error +ChkFipsMode(char *arg) +{ + if(!PORT_Strcasecmp(arg, "true")) { + if (PK11_IsFIPS()) { + PR_fprintf(PR_STDOUT, msgStrings[FIPS_ENABLED_MSG]); + } else { + PR_fprintf(PR_STDOUT, msgStrings[FIPS_DISABLED_MSG]); + return FIPS_SWITCH_FAILED_ERR; + } + + } else if(!PORT_Strcasecmp(arg, "false")) { + if(!PK11_IsFIPS()) { + PR_fprintf(PR_STDOUT, msgStrings[FIPS_DISABLED_MSG]); + } else { + PR_fprintf(PR_STDOUT, msgStrings[FIPS_ENABLED_MSG]); + return FIPS_SWITCH_FAILED_ERR; + } + } else { + PR_fprintf(PR_STDERR, errStrings[INVALID_FIPS_ARG]); + return INVALID_FIPS_ARG; + } + + return SUCCESS; +} + +/************************************************************************ + * Cipher and Mechanism name-bitmask translation tables + */ + +typedef struct { + char *name; + unsigned long mask; +} MaskString; + +static MaskString mechanismStrings[] = { + {"RSA", PUBLIC_MECH_RSA_FLAG}, + {"DSA", PUBLIC_MECH_DSA_FLAG}, + {"RC2", PUBLIC_MECH_RC2_FLAG}, + {"RC4", PUBLIC_MECH_RC4_FLAG}, + {"RC5", PUBLIC_MECH_RC5_FLAG}, + {"DES", PUBLIC_MECH_DES_FLAG}, + {"DH", PUBLIC_MECH_DH_FLAG}, + {"FORTEZZA", PUBLIC_MECH_FORTEZZA_FLAG}, + {"SHA1", PUBLIC_MECH_SHA1_FLAG}, + {"MD5", PUBLIC_MECH_MD5_FLAG}, + {"MD2", PUBLIC_MECH_MD2_FLAG}, + {"SSL", PUBLIC_MECH_SSL_FLAG}, + {"TLS", PUBLIC_MECH_TLS_FLAG}, + {"RANDOM", PUBLIC_MECH_RANDOM_FLAG}, + {"FRIENDLY", PUBLIC_MECH_FRIENDLY_FLAG} +}; +static int numMechanismStrings = + sizeof(mechanismStrings) / sizeof(mechanismStrings[0]); + +static MaskString cipherStrings[] = { + {"FORTEZZA", PUBLIC_CIPHER_FORTEZZA_FLAG} +}; +static int numCipherStrings = + sizeof(cipherStrings) / sizeof(cipherStrings[0]); + +/* Maximum length of a colon-separated list of all the strings in an + * array. */ +#define MAX_STRING_LIST_LEN 240 /* or less */ + +/************************************************************************ + * + * g e t F l a g s F r o m S t r i n g + * + * Parses a mechanism list passed on the command line and converts it + * to an unsigned long bitmask. + * string is a colon-separated string of constants + * array is an array of MaskStrings. + * elements is the number of elements in array. + */ +static unsigned long +getFlagsFromString(char *string, MaskString array[], int elements) +{ + unsigned long ret = 0; + short i = 0; + char *cp; + char *buf; + char *end; + + if(!string || !string[0]) { + return ret; + } + + /* Make a temporary copy of the string */ + buf = PR_Malloc(strlen(string)+1); + if(!buf) { + out_of_memory(); + } + strcpy(buf, string); + + /* Look at each element of the list passed in */ + for(cp=buf; cp && *cp; cp = (end ? end+1 : NULL) ) { + /* Look at the string up to the next colon */ + end = strchr(cp, ':'); + if(end) { + *end = '\0'; + } + + /* Find which element this is */ + for(i=0; i < elements; i++) { + if( !PORT_Strcasecmp(cp, array[i].name) ) { + break; + } + } + if(i == elements) { + /* Skip a bogus string, but print a warning message */ + PR_fprintf(PR_STDERR, errStrings[INVALID_CONSTANT_ERR], cp); + continue; + } + ret |= array[i].mask; + } + + PR_Free(buf); + return ret; +} + +/********************************************************************** + * + * g e t S t r i n g F r o m F l a g s + * + * The return string's memory is owned by this function. Copy it + * if you need it permanently or you want to change it. + */ +static char * +getStringFromFlags(unsigned long flags, MaskString array[], int elements) +{ + static char buf[MAX_STRING_LIST_LEN]; + int i; + int count=0; + + buf[0] = '\0'; + for(i=0; i<elements; i++) { + if( flags & array[i].mask ) { + ++count; + if(count!=1) { + strcat(buf, ":"); + } + strcat(buf, array[i].name); + } + } + return buf; +} + +/********************************************************************** + * + * A d d M o d u l e + * + * Add the named module, with the given library file, ciphers, and + * default mechanism flags + */ +Error +AddModule(char *moduleName, char *libFile, char *cipherString, + char *mechanismString, char* modparms) +{ + unsigned long ciphers; + unsigned long mechanisms; + SECStatus status; + + mechanisms = + getFlagsFromString(mechanismString, mechanismStrings, + numMechanismStrings); + ciphers = + getFlagsFromString(cipherString, cipherStrings, numCipherStrings); + + status = + SECMOD_AddNewModuleEx(moduleName, libFile, + SECMOD_PubMechFlagstoInternal(mechanisms), + SECMOD_PubCipherFlagstoInternal(ciphers), + modparms, NULL ); + + if(status != SECSuccess) { + char* errtxt=NULL; + PRInt32 copied = 0; + if (PR_GetErrorTextLength()) { + errtxt = PR_Malloc(PR_GetErrorTextLength()); + copied = PR_GetErrorText(errtxt); + } + if (copied && errtxt) { + PR_fprintf(PR_STDERR, errStrings[ADD_MODULE_FAILED_STATUS_ERR], moduleName, errtxt); + PR_Free(errtxt); + } + else { + PR_fprintf(PR_STDERR, errStrings[ADD_MODULE_FAILED_ERR], moduleName); + } + return ADD_MODULE_FAILED_ERR; + } else { + PR_fprintf(PR_STDOUT, msgStrings[ADD_MODULE_SUCCESS_MSG], moduleName); + return SUCCESS; + } +} + +/*********************************************************************** + * + * D e l e t e M o d u l e + * + * Deletes the named module from the database. + */ +Error +DeleteModule(char *moduleName) +{ + SECStatus status; + int type; + + status = SECMOD_DeleteModule(moduleName, &type); + + if(status != SECSuccess) { + if(type == SECMOD_FIPS || type == SECMOD_INTERNAL) { + PR_fprintf(PR_STDERR, errStrings[DELETE_INTERNAL_ERR]); + return DELETE_INTERNAL_ERR; + } else { + PR_fprintf(PR_STDERR, errStrings[DELETE_FAILED_ERR], moduleName); + return DELETE_FAILED_ERR; + } + } + + PR_fprintf(PR_STDOUT, msgStrings[DELETE_SUCCESS_MSG], moduleName); + return SUCCESS; +} + +/************************************************************************ + * + * R a w L i s t M o d u l e s + * + * Lists all the modules in the database, along with their slots and tokens. + */ +Error +RawListModule(char *modulespec) +{ + SECMODModule *module; + char **moduleSpecList; + + module = SECMOD_LoadModule(modulespec,NULL,PR_FALSE); + if (module == NULL) { + /* handle error */ + return NO_SUCH_MODULE_ERR; + } + + moduleSpecList = SECMOD_GetModuleSpecList(module); + + for ( ;*moduleSpecList; moduleSpecList++) { + printf("%s\n",*moduleSpecList); + } + + return SUCCESS; +} + +Error +RawAddModule(char *dbmodulespec, char *modulespec) +{ + SECMODModule *module; + SECMODModule *dbmodule; + + + dbmodule = SECMOD_LoadModule(dbmodulespec,NULL,PR_TRUE); + if (dbmodule == NULL) { + /* handle error */ + return NO_SUCH_MODULE_ERR; + } + + module = SECMOD_LoadModule(modulespec,dbmodule,PR_FALSE); + if (module == NULL) { + /* handle error */ + return NO_SUCH_MODULE_ERR; + } + + if( SECMOD_UpdateModule(module) != SECSuccess ) { + PR_fprintf(PR_STDERR, errStrings[UPDATE_MOD_FAILED_ERR], modulespec); + return UPDATE_MOD_FAILED_ERR; + } + return SUCCESS; +} + +/************************************************************************ + * + * L i s t M o d u l e s + * + * Lists all the modules in the database, along with their slots and tokens. + */ +Error +ListModules() +{ + SECMODListLock *lock; + SECMODModuleList *list; + SECMODModuleList *mlp; + Error ret=UNSPECIFIED_ERR; + int count = 0, i; + + lock = SECMOD_GetDefaultModuleListLock(); + if(!lock) { + PR_fprintf(PR_STDERR, errStrings[NO_LIST_LOCK_ERR]); + return NO_LIST_LOCK_ERR; + } + + SECMOD_GetReadLock(lock); + + list = SECMOD_GetDefaultModuleList(); + if(!list) { + PR_fprintf(PR_STDERR, errStrings[NO_MODULE_LIST_ERR]); + ret = NO_MODULE_LIST_ERR; + goto loser; + } + + PR_fprintf(PR_STDOUT, + "\nListing of PKCS #11 Modules\n" + "-----------------------------------------------------------\n"); + + for(mlp=list; mlp != NULL; mlp = mlp->next) { + ++count; + if(count!=1) { + PR_fprintf(PR_STDOUT, "\n"); + } + + PR_fprintf(PR_STDOUT, "%3d. %s\n", count, mlp->module->commonName); + + if(mlp->module->dllName) { + PR_fprintf(PR_STDOUT, "\tlibrary name: %s\n", mlp->module->dllName); + } + + if(mlp->module->slotCount == 0) { + PR_fprintf(PR_STDOUT, + "\t slots: There are no slots attached to this module\n"); + } else { + PR_fprintf(PR_STDOUT, + "\t slots: %d slot%s attached\n", mlp->module->slotCount, + (mlp->module->slotCount==1 ? "" : "s") ); + } + + if(mlp->module->loaded == 0) { + PR_fprintf(PR_STDOUT, "\tstatus: Not loaded\n"); + } else { + PR_fprintf(PR_STDOUT, "\tstatus: loaded\n"); + } + + /* Print slot and token names */ + for (i = 0; i < mlp->module->slotCount; i++) { + PK11SlotInfo *slot = mlp->module->slots[i]; + + PR_fprintf(PR_STDOUT, "\n"); + PR_fprintf(PR_STDOUT, "\t slot: %s\n", PK11_GetSlotName(slot)); + PR_fprintf(PR_STDOUT, "\ttoken: %s\n", PK11_GetTokenName(slot)); + } + } + + PR_fprintf(PR_STDOUT, + "-----------------------------------------------------------\n"); + + ret = SUCCESS; + +loser: + SECMOD_ReleaseReadLock(lock); + return ret; +} + +/* Strings describing PK11DisableReasons */ +static char *disableReasonStr[] = { + "no reason", + "user disabled", + "could not initialize token", + "could not verify token", + "token not present" +}; +static int numDisableReasonStr = + sizeof(disableReasonStr) / sizeof(disableReasonStr[0]); + +/*********************************************************************** + * + * L i s t M o d u l e + * + * Lists detailed information about the named module. + */ +Error +ListModule(char *moduleName) +{ + SECMODModule *module; + PK11SlotInfo *slot; + int slotnum; + CK_INFO modinfo; + CK_SLOT_INFO slotinfo; + CK_TOKEN_INFO tokeninfo; + char *ciphers, *mechanisms; + PK11DisableReasons reason; + Error rv = SUCCESS; + + if(!moduleName) { + return SUCCESS; + } + + module = SECMOD_FindModule(moduleName); + if(!module) { + PR_fprintf(PR_STDERR, errStrings[NO_SUCH_MODULE_ERR], moduleName); + return NO_SUCH_MODULE_ERR; + } + + if(PK11_GetModInfo(module, &modinfo) != SECSuccess) { + PR_fprintf(PR_STDERR, errStrings[MOD_INFO_ERR], moduleName); + return MOD_INFO_ERR; + } + + /* Module info */ + PR_fprintf(PR_STDOUT, + "\n-----------------------------------------------------------\n"); + PR_fprintf(PR_STDOUT, "Name: %s\n", module->commonName); + if(module->internal || !module->dllName) { + PR_fprintf(PR_STDOUT, "Library file: **Internal ONLY module**\n"); + } else { + PR_fprintf(PR_STDOUT, "Library file: %s\n", module->dllName); + } + + PR_fprintf(PR_STDOUT, "Manufacturer: %.32s\n", modinfo.manufacturerID); + PR_fprintf(PR_STDOUT, "Description: %.32s\n", modinfo.libraryDescription); + PR_fprintf(PR_STDOUT, "PKCS #11 Version %d.%d\n", + modinfo.cryptokiVersion.major, modinfo.cryptokiVersion.minor); + PR_fprintf(PR_STDOUT, "Library Version: %d.%d\n", + modinfo.libraryVersion.major, modinfo.libraryVersion.minor); + + /* Get cipher and mechanism flags */ + ciphers = getStringFromFlags(module->ssl[0], cipherStrings, + numCipherStrings); + if(ciphers[0] == '\0') { + ciphers = "None"; + } + PR_fprintf(PR_STDOUT, "Cipher Enable Flags: %s\n", ciphers); + mechanisms = NULL; + if(module->slotCount > 0) { + mechanisms = getStringFromFlags( + PK11_GetDefaultFlags(module->slots[0]), + mechanismStrings, numMechanismStrings); + } + if(mechanisms[0] =='\0') { + mechanisms = "None"; + } + PR_fprintf(PR_STDOUT, "Default Mechanism Flags: %s\n", mechanisms); + +#define PAD " " + + /* Loop over each slot */ + for(slotnum=0; slotnum < module->slotCount; slotnum++) { + slot = module->slots[slotnum]; + if(PK11_GetSlotInfo(slot, &slotinfo) != SECSuccess) { + PR_fprintf(PR_STDERR, errStrings[SLOT_INFO_ERR], + PK11_GetSlotName(slot)); + rv = SLOT_INFO_ERR; + continue; + } + + /* Slot Info */ + PR_fprintf(PR_STDOUT, "\n"PAD"Slot: %s\n", PK11_GetSlotName(slot)); + mechanisms = getStringFromFlags(PK11_GetDefaultFlags(slot), + mechanismStrings, numMechanismStrings); + if(mechanisms[0] =='\0') { + mechanisms = "None"; + } + PR_fprintf(PR_STDOUT, PAD"Slot Mechanism Flags: %s\n", mechanisms); + PR_fprintf(PR_STDOUT, PAD"Manufacturer: %.32s\n", + slotinfo.manufacturerID); + if (PK11_IsHW(slot)) { + PR_fprintf(PR_STDOUT, PAD"Type: Hardware\n"); + } else { + PR_fprintf(PR_STDOUT, PAD"Type: Software\n"); + } + PR_fprintf(PR_STDOUT, PAD"Version Number: %d.%d\n", + slotinfo.hardwareVersion.major, slotinfo.hardwareVersion.minor); + PR_fprintf(PR_STDOUT, PAD"Firmware Version: %d.%d\n", + slotinfo.firmwareVersion.major, slotinfo.firmwareVersion.minor); + if (PK11_IsDisabled(slot)) { + reason = PK11_GetDisabledReason(slot); + if(reason < numDisableReasonStr) { + PR_fprintf(PR_STDOUT, PAD"Status: DISABLED (%s)\n", + disableReasonStr[reason]); + } else { + PR_fprintf(PR_STDOUT, PAD"Status: DISABLED\n"); + } + } else { + PR_fprintf(PR_STDOUT, PAD"Status: Enabled\n"); + } + + if(PK11_GetTokenInfo(slot, &tokeninfo) != SECSuccess) { + PR_fprintf(PR_STDERR, errStrings[TOKEN_INFO_ERR], + PK11_GetTokenName(slot)); + rv = TOKEN_INFO_ERR; + continue; + } + + /* Token Info */ + PR_fprintf(PR_STDOUT, PAD"Token Name: %.32s\n", + tokeninfo.label); + PR_fprintf(PR_STDOUT, PAD"Token Manufacturer: %.32s\n", + tokeninfo.manufacturerID); + PR_fprintf(PR_STDOUT, PAD"Token Model: %.16s\n", tokeninfo.model); + PR_fprintf(PR_STDOUT, PAD"Token Serial Number: %.16s\n", + tokeninfo.serialNumber); + PR_fprintf(PR_STDOUT, PAD"Token Version: %d.%d\n", + tokeninfo.hardwareVersion.major, tokeninfo.hardwareVersion.minor); + PR_fprintf(PR_STDOUT, PAD"Token Firmware Version: %d.%d\n", + tokeninfo.firmwareVersion.major, tokeninfo.firmwareVersion.minor); + if(tokeninfo.flags & CKF_WRITE_PROTECTED) { + PR_fprintf(PR_STDOUT, PAD"Access: Write Protected\n"); + } else { + PR_fprintf(PR_STDOUT, PAD"Access: NOT Write Protected\n"); + } + if(tokeninfo.flags & CKF_LOGIN_REQUIRED) { + PR_fprintf(PR_STDOUT, PAD"Login Type: Login required\n"); + } else { + PR_fprintf(PR_STDOUT, PAD + "Login Type: Public (no login required)\n"); + } + if(tokeninfo.flags & CKF_USER_PIN_INITIALIZED) { + PR_fprintf(PR_STDOUT, PAD"User Pin: Initialized\n"); + } else { + PR_fprintf(PR_STDOUT, PAD"User Pin: NOT Initialized\n"); + } + } + PR_fprintf(PR_STDOUT, + "\n-----------------------------------------------------------\n"); + return rv; +} + +/************************************************************************ + * + * C h a n g e P W + */ +Error +ChangePW(char *tokenName, char *pwFile, char *newpwFile) +{ + char *oldpw=NULL, *newpw=NULL, *newpw2=NULL; + PK11SlotInfo *slot; + Error ret=UNSPECIFIED_ERR; + PRBool matching; + + slot = PK11_FindSlotByName(tokenName); + if(!slot) { + PR_fprintf(PR_STDERR, errStrings[NO_SUCH_TOKEN_ERR], tokenName); + return NO_SUCH_TOKEN_ERR; + } + + PK11_SetPasswordFunc(SECU_GetModulePassword); + + /* Get old password */ + if(! PK11_NeedUserInit(slot)) { + if(pwFile) { + oldpw = SECU_FilePasswd(NULL, PR_FALSE, pwFile); + if(PK11_CheckUserPassword(slot, oldpw) != SECSuccess) { + PR_fprintf(PR_STDERR, errStrings[BAD_PW_ERR]); + ret=BAD_PW_ERR; + goto loser; + } + } else { + for(matching=PR_FALSE; !matching; ) { + oldpw = SECU_GetPasswordString(NULL, "Enter old password: "); + if(PK11_CheckUserPassword(slot, oldpw) == SECSuccess) { + matching = PR_TRUE; + } else { + PR_fprintf(PR_STDOUT, msgStrings[BAD_PW_MSG]); + } + } + } + } + + /* Get new password */ + if(newpwFile) { + newpw = SECU_FilePasswd(NULL, PR_FALSE, newpwFile); + } else { + for(matching=PR_FALSE; !matching; ) { + newpw = SECU_GetPasswordString(NULL, "Enter new password: "); + newpw2 = SECU_GetPasswordString(NULL, "Re-enter new password: "); + if(strcmp(newpw, newpw2)) { + PR_fprintf(PR_STDOUT, msgStrings[PW_MATCH_MSG]); + } else { + matching = PR_TRUE; + } + } + } + + /* Change the password */ + if(PK11_NeedUserInit(slot)) { + if(PK11_InitPin(slot, NULL /*ssopw*/, newpw) != SECSuccess) { + PR_fprintf(PR_STDERR, errStrings[CHANGEPW_FAILED_ERR], tokenName); + ret = CHANGEPW_FAILED_ERR; + goto loser; + } + } else { + if(PK11_ChangePW(slot, oldpw, newpw) != SECSuccess) { + PR_fprintf(PR_STDERR, errStrings[CHANGEPW_FAILED_ERR], tokenName); + ret = CHANGEPW_FAILED_ERR; + goto loser; + } + } + + PR_fprintf(PR_STDOUT, msgStrings[CHANGEPW_SUCCESS_MSG], tokenName); + ret = SUCCESS; + +loser: + if(oldpw) { + memset(oldpw, 0, strlen(oldpw)); + PORT_Free(oldpw); + } + if(newpw) { + memset(newpw, 0, strlen(newpw)); + PORT_Free(newpw); + } + if(newpw2) { + memset(newpw2, 0, strlen(newpw)); + PORT_Free(newpw2); + } + return ret; +} + +/*********************************************************************** + * + * E n a b l e M o d u l e + * + * If enable==PR_TRUE, enables the module or slot. + * If enable==PR_FALSE, disables the module or slot. + * moduleName is the name of the module. + * slotName is the name of the slot. It is optional. + */ +Error +EnableModule(char *moduleName, char *slotName, PRBool enable) +{ + int i; + SECMODModule *module; + PK11SlotInfo *slot = NULL; + PRBool found = PR_FALSE; + + module = SECMOD_FindModule(moduleName); + if(!module) { + PR_fprintf(PR_STDERR, errStrings[NO_SUCH_MODULE_ERR], moduleName); + return NO_SUCH_MODULE_ERR; + } + + for(i=0; i < module->slotCount; i++) { + slot = module->slots[i]; + if(slotName && strcmp(PK11_GetSlotName(slot), slotName)) { + /* Not the right slot */ + continue; + } + if(enable) { + if(! PK11_UserEnableSlot(slot)) { + PR_fprintf(PR_STDERR, errStrings[ENABLE_FAILED_ERR], + "enable", PK11_GetSlotName(slot)); + return ENABLE_FAILED_ERR; + } else { + found = PR_TRUE; + PR_fprintf(PR_STDOUT, msgStrings[ENABLE_SUCCESS_MSG], + PK11_GetSlotName(slot), "enabled"); + } + } else { + if(! PK11_UserDisableSlot(slot)) { + PR_fprintf(PR_STDERR, errStrings[ENABLE_FAILED_ERR], + "disable", PK11_GetSlotName(slot)); + return ENABLE_FAILED_ERR; + } else { + found = PR_TRUE; + PR_fprintf(PR_STDOUT, msgStrings[ENABLE_SUCCESS_MSG], + PK11_GetSlotName(slot), "disabled"); + } + } + } + + if(slotName && !found) { + PR_fprintf(PR_STDERR, errStrings[NO_SUCH_SLOT_ERR], slotName); + return NO_SUCH_SLOT_ERR; + } + + /* Delete and re-add module to save changes */ + if( SECMOD_UpdateModule(module) != SECSuccess ) { + PR_fprintf(PR_STDERR, errStrings[UPDATE_MOD_FAILED_ERR], moduleName); + return UPDATE_MOD_FAILED_ERR; + } + + return SUCCESS; +} + +/************************************************************************* + * + * S e t D e f a u l t M o d u l e + * + */ +Error +SetDefaultModule(char *moduleName, char *slotName, char *mechanisms) +{ + SECMODModule *module; + PK11SlotInfo *slot; + int s, i; + unsigned long mechFlags = getFlagsFromString(mechanisms, mechanismStrings, + numMechanismStrings); + PRBool found = PR_FALSE; + Error errcode = UNSPECIFIED_ERR; + + if (pk11_DefaultArray == NULL) { + pk11_DefaultArray = PK11_GetDefaultArray(&pk11_DefaultArraySize); + if (pk11_DefaultArray == NULL) { + /* should assert. This shouldn't happen */ + goto loser; + } + } + + mechFlags = SECMOD_PubMechFlagstoInternal(mechFlags); + + module = SECMOD_FindModule(moduleName); + if(!module) { + PR_fprintf(PR_STDERR, errStrings[NO_SUCH_MODULE_ERR], moduleName); + errcode = NO_SUCH_MODULE_ERR; + goto loser; + } + + /* Go through each slot */ + for(s=0; s < module->slotCount; s++) { + slot = module->slots[s]; + + if ((slotName != NULL) && + !((strcmp(PK11_GetSlotName(slot),slotName) == 0) || + (strcmp(PK11_GetTokenName(slot),slotName) == 0)) ) { + /* we are only interested in changing the one slot */ + continue; + } + + found = PR_TRUE; + + /* Go through each mechanism */ + for(i=0; i < pk11_DefaultArraySize; i++) { + if(pk11_DefaultArray[i].flag & mechFlags) { + /* Enable this default mechanism */ + PK11_UpdateSlotAttribute(slot, &(pk11_DefaultArray[i]), + PR_TRUE); + } + } + } + if (slotName && !found) { + PR_fprintf(PR_STDERR, errStrings[NO_SUCH_SLOT_ERR], slotName); + errcode = NO_SUCH_SLOT_ERR; + goto loser; + } + + /* Delete and re-add module to save changes */ + if( SECMOD_UpdateModule(module) != SECSuccess ) { + PR_fprintf(PR_STDERR, errStrings[DEFAULT_FAILED_ERR], + moduleName); + errcode = DEFAULT_FAILED_ERR; + goto loser; + } + + PR_fprintf(PR_STDOUT, msgStrings[DEFAULT_SUCCESS_MSG]); + + errcode = SUCCESS; +loser: + return errcode; +} + +/************************************************************************ + * + * U n s e t D e f a u l t M o d u l e + */ +Error +UnsetDefaultModule(char *moduleName, char *slotName, char *mechanisms) +{ + SECMODModule * module; + PK11SlotInfo *slot; + int s, i; + unsigned long mechFlags = getFlagsFromString(mechanisms, + mechanismStrings, numMechanismStrings); + PRBool found = PR_FALSE; + + if (pk11_DefaultArray == NULL) { + pk11_DefaultArray = PK11_GetDefaultArray(&pk11_DefaultArraySize); + if (pk11_DefaultArray == NULL) { + /* should assert. This shouldn't happen */ + return UNSPECIFIED_ERR; + } + } + + mechFlags = SECMOD_PubMechFlagstoInternal(mechFlags); + + module = SECMOD_FindModule(moduleName); + if(!module) { + PR_fprintf(PR_STDERR, errStrings[NO_SUCH_MODULE_ERR], moduleName); + return NO_SUCH_MODULE_ERR; + } + + for(s=0; s < module->slotCount; s++) { + slot = module->slots[s]; + if ((slotName != NULL) && + !((strcmp(PK11_GetSlotName(slot),slotName) == 0) || + (strcmp(PK11_GetTokenName(slot),slotName) == 0)) ) { + /* we are only interested in changing the one slot */ + continue; + } + for(i=0; i < pk11_DefaultArraySize ; i++) { + if(pk11_DefaultArray[i].flag & mechFlags) { + PK11_UpdateSlotAttribute(slot, &(pk11_DefaultArray[i]), + PR_FALSE); + } + } + } + if (slotName && !found) { + PR_fprintf(PR_STDERR, errStrings[NO_SUCH_SLOT_ERR], slotName); + return NO_SUCH_SLOT_ERR; + } + + /* Delete and re-add module to save changes */ + if( SECMOD_UpdateModule(module) != SECSuccess ) { + PR_fprintf(PR_STDERR, errStrings[UNDEFAULT_FAILED_ERR], + moduleName); + return UNDEFAULT_FAILED_ERR; + } + + PR_fprintf(PR_STDOUT, msgStrings[UNDEFAULT_SUCCESS_MSG]); + return SUCCESS; +} diff --git a/security/nss/cmd/modutil/pk11jar.html b/security/nss/cmd/modutil/pk11jar.html new file mode 100644 index 000000000..9440db014 --- /dev/null +++ b/security/nss/cmd/modutil/pk11jar.html @@ -0,0 +1,309 @@ +<html> +<!-- + - The contents of this file are subject to the Mozilla Public + - License Version 1.1 (the "License"); you may not use this file + - except in compliance with the License. You may obtain a copy of + - the License at http://www.mozilla.org/MPL/ + - + - Software distributed under the License is distributed on an "AS + - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + - implied. See the License for the specific language governing + - rights and limitations under 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. + --> +<head> +<title>PKCS #11 JAR Format</title> +</head> +<body bgcolor=white text=black link=blue vlink=purple alink=red> +<center><h1>PKCS #11 JAR Format</h1></center> + +<p>PKCS #11 modules can be packaged into JAR files that support automatic +installation onto the filesystem and into the security module database. +The JAR file should contain: +<ul> +<li>All files that will be installed onto the target machine. This will +include at least the PKCS #11 module library file (.DLL or .so), and +may also include any other file that should be installed (such as +documentation). +<li>A script to perform the installation. +</ul> +The script can be in one of two forms. If the JAR file is to be +run by Communicator (or any program that interprets Javascript), the +instructions will be in the form of a SmartUpdate script. +<a href="http://devedge/library/documentation/security/jmpkcs/">Documentation +</a> on creating this script can be found on DevEdge. + +<p>If the +JAR file is to be run by a server, modutil, or any other program that +doesn't interpret Javascript, a special information file must be included +in the format described in this document. + +<h2>Declaring the Script in the Manifest File</h2> +The script can have any name, but it must be declared in the manifest file +of the JAR archive. The metainfo tag for this is +<code>Pkcs11_install_script</code>. Meta-information is put in the manifest +file by putting it in a file which is passed to +<a href="http://developer.netscape.com/software/index_frame.html?content=signedobj/jarpack.html#signtool1.3">Signtool</a>. For example, +suppose the PKCS #11 installer script is in the file <code>pk11install</code>. +In Signtool's metainfo file, you would have a line like this: +<blockquote><pre> ++ Pkcs11_install_script: pk11install +</pre></blockquote> + +<h2>Sample Script File</h2> +<blockquote><pre> +ForwardCompatible { IRIX:6.2:mips Solaris:5.5.1:sparc } +Platforms { + WINNT::x86 { + ModuleName { "Fortezza Module" } + ModuleFile { win32/fort32.dll } + DefaultMechanismFlags{0x0001} + DefaultCipherFlags{0x0001} + Files { + win32/setup.exe { + Executable + RelativePath { %temp%/setup.exe } + } + win32/setup.hlp { + RelativePath { %temp%/setup.hlp } + } + win32/setup.cab { + RelativePath { %temp%/setup.cab } + } + } + } + WIN95::x86 { + EquivalentPlatform {WINNT::x86} + } + Solaris:5.5.1:sparc { + ModuleName { "Fortezza UNIX Module" } + ModuleFile { unix/fort.so } + DefaultMechanismFlags{0x0001} + CipherEnableFlags{0x0001} + Files { + unix/fort.so { + RelativePath{%root%/lib/fort.so} + AbsolutePath{/usr/local/netscape/lib/fort.so} + FilePermissions{555} + } + xplat/instr.html { + RelativePath{%root%/docs/inst.html} + AbsolutePath{/usr/local/netscape/docs/inst.html} + FilePermissions{555} + } + } + } + IRIX:6.2:mips { + EquivalentPlatform { Solaris:5.5.1:sparc } + } +} +</pre></blockquote> + +<hr> + +<h2>Script File Grammar</h2> +<blockquote><pre> +--> <i>valuelist</i> + +<i>valuelist</i> --> <i>value</i> <i>valuelist</i> +<i> </i> <i><null></i> + +<i>value</i> --> <i>key_value_pair</i> +<i> </i> <i>string</i> + +<i>key_value_pair</i> --> <i>key</i> { <i>valuelist</i> } + +<i>key</i> --> <i>string</i> + +<i>string</i> --> <i>simple_string</i> +<i> </i> "<i>complex_string</i>" + +<i>simple_string</i> --> [^ \t\n\""{""}"]+ <font size=-1><i>(no whitespace, quotes, or braces)</i></font> + +<i>complex_string</i> --> ([^\"\\\r\n]|(\\\")|(\\\\))+ <font size=-1><i>(quotes and backslashes must be escaped with a backslash, no newlines or carriage returns are allowed in the string)</i></font> +</pre></blockquote> +Outside of complex strings, all whitespace (space, tab, newline) is considered +equal and is used only to delimit tokens. + +<hr> + +<h2>Keys</h2> +Keys are case-insensitive. +<h3>Global Keys</h3> +<dl> +<dt><code>ForwardCompatible</code> +<dd>Gives a list of platforms that are forward compatible. If the current +platform cannot be found in the list of supported platforms, then the +ForwardCompatible list will be checked for any platforms that have the same +OS and architecture and an earlier version. If one is found, its +attributes will be used for the current platform. +<dt><code>Platforms</code> (<i>required</i>) +<dd>Gives a list of platforms. Each entry in the list is itself a key-value +pair: +the key is the name of the platform, and the valuelist contains various +attributes of the platform. The ModuleName, ModuleFile, and Files attributes +must be specified, unless an EquivalentPlatform attribute is specified. +The platform string is in the following +format: <u><i>system name</i></u>:<u><i>os release</i></u>:<u><i>architecture</i></u>. The installer +will obtain these values from NSPR. <u><i>os release</i></u> is an empty +string on non-UNIX operating systems. The following system names and platforms +are currently defined by NSPR:<code> +<ul> +<li>AIX (rs6000) +<li>BSDI (x86) +<li>FREEBSD (x86) +<li>HPUX (hppa1.1) +<li>IRIX (mips) +<li>LINUX (ppc, alpha, x86) +<li>MacOS (PowerPC) </code>(<i>Note: NSPR actually defines the OS as +"</i><code>Mac OS</code><i>". The +space makes the name unsuitable for being embedded in identifiers. Until +NSPR changes, you will have to add some special code to deal with this case. +</i>)<code> +<li>NCR (x86) +<li>NEC (mips) +<li>OS2 (x86) +<li>OSF (alpha) +<li>ReliantUNIX (mips) +<li>SCO (x86) +<li>SOLARIS (sparc) +<li>SONY (mips) +<li>SUNOS (sparc) +<li>UnixWare (x86) +<li>WIN16 (x86) +<li>WIN95 (x86) +<li>WINNT (x86) +</ul> +</code> +Examples of valid platform strings: <code>IRIX:6.2:mips, Solaris:5.5.1:sparc, +Linux:2.0.32:x86, WIN95::x86</code>. +</dl> + +<h3>Per-Platform Keys</h3> +These keys only have meaning within the value list of an entry in +the <code>Platforms</code> list. +<dl> +<dt><code>ModuleName</code> (<i>required</i>) +<dd>Gives the common name for the module. This name will be used to +reference the module from Communicator, modutil, servers, or any other +program that uses the Netscape security module database. +<dt><code>ModuleFile</code> (<i>required</i>) +<dd>Names the PKCS #11 module file (DLL or .so) for this platform. The name +is given as the relative path of the file within the JAR archive. +<dt><code>Files</code> (<i>required</i>) +<dd>Lists the files that should be installed for this module. Each entry +in the file list is a key-value pair: the key is the path of the file in +the JAR archive, and +the valuelist contains attributes of the file. At least RelativePath and +AbsoluteDir must be specified in this valuelist. +<dt><code>DefaultMechanismFlags</code> +<dd>This key-value pair specifies +of which mechanisms this module will be a default provider. It is a bitstring +specified in hexadecimal (0x) format. It is constructed as a bitwise OR +of the following constants. If the <code>DefaultMechanismFlags</code> +entry is omitted, the value will default to 0x0. +<blockquote><pre> +RSA: 0x0000 0001 +DSA: 0x0000 0002 +RC2: 0x0000 0004 +RC4: 0x0000 0008 +DES: 0x0000 0010 +DH: 0x0000 0020 +FORTEZZA: 0x0000 0040 +RC5: 0x0000 0080 +SHA1: 0x0000 0100 +MD5: 0x0000 0200 +MD2: 0x0000 0400 +RANDOM: 0x0800 0000 +FRIENDLY: 0x1000 0000 +OWN_PW_DEFAULTS: 0x2000 0000 +DISABLE: 0x4000 0000 +</pre></blockquote> +<dt><code>CipherEnableFlags</code> +<dd>This key-value pair specifies +which SSL ciphers will be enabled. It is a bitstring specified in +hexadecimal (0x) format. It is constructed as a bitwise OR of the following +constants. If the <code>CipherEnableFlags</code> entry is omitted, the +value will default to 0x0. +<blockquote><pre> +FORTEZZA: 0x0000 0001 +</pre></blockquote> +<dt><code>EquivalentPlatform</code> +<dd>Specifies that the attributes of the named platform should also be used +for the current platform. Saves typing when there is more than one platform +that uses the same settings. +</dl> + +<h3>Per-File Keys</h3> +These keys only have meaning within the valuelist of an entry in a +<code>Files</code> list. At least one of <code>RelativePath</code> and +<code>AbsolutePath</code> must be specified. If both are specified, the +relative path will be tried first and the absolute path used only if no +relative root directory is provided by the installer program. +<dl> +<dt><code>RelativePath</code> +<dd>Specifies the destination directory of the file, relative to some directory +decided at install-time. Two variables can be used in the relative +path, "%root%" and "%temp%". "%root%" will be replaced at run-time with +the directory relative to which files should be installed; for +example, it may be the server's root directory or Communicator's root +directory. "%temp%" is a directory that will be created at the beginning +of the installation and destroyed at the end of the installation. Its purpose +is to hold executable files (such as setup programs), or files that are +used by these programs. For example, a Windows installation might consist +of a <code>setup.exe</code> installation program, a help file, and a .cab file +containing compressed information. All these files could be installed into the +temporary directory. Files destined for the temporary directory are guaranteed +to be in place before any executable file is run, and will not be deleted +until all executable files have finished. +<dt><code>AbsoluteDir</code> +<dd>Specifies the destination directory of the file as an absolute path. +This will only be used if the installer is unable to determine a +relative directory. +<dt><code>Executable</code> +<dd>This string specifies that the file is to be executed during the +course of the +installation. Typically this would be used for a setup program provided +by a module vendor, such as a self-extracting <code>setup.exe</code>. +More than one file can be specified as executable, in which case they will +be run in the order they are specified in the script file. +<dt><code>FilePermissions</code> +<dd>This string is interpreted as a string of octal digits, according to the +standard UNIX format. It is a bitwise OR of the following constants: +<blockquote><pre> +user read: 400 +user write: 200 +user execute: 100 +group read: 040 +group write: 020 +group execute: 010 +other read: 004 +other write: 002 +other execute: 001 +</pre></blockquote> +Some platforms may not understand these permissions. They will only be +applied insofar as makes sense for the current platform. If this attribute +is omitted, a default of 777 is assumed. + +</body> +</html> diff --git a/security/nss/cmd/modutil/rules.mk b/security/nss/cmd/modutil/rules.mk new file mode 100644 index 000000000..b34662513 --- /dev/null +++ b/security/nss/cmd/modutil/rules.mk @@ -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. +# + +# +# Some versions of yacc generate files that include platform-specific +# system headers. For example, the yacc in Solaris 2.6 inserts +# #include <values.h> +# which does not exist on NT. For portability, always use Berkeley +# yacc (such as the yacc in Linux) to generate files. +# + +generate: installparse.c installparse.l + +installparse.c: + yacc -p Pk11Install_yy -d installparse.y + mv y.tab.c installparse.c + mv y.tab.h installparse.h + +installparse.l: + lex -olex.Pk11Install_yy.c -PPk11Install_yy installparse.l + @echo + @echo "**YOU MUST COMMENT OUT UNISTD.H FROM lex.Pk11Install_yy.cpp**" + +install.c: install-ds.h install.h diff --git a/security/nss/cmd/modutil/specification.html b/security/nss/cmd/modutil/specification.html new file mode 100644 index 000000000..48a1ab7cd --- /dev/null +++ b/security/nss/cmd/modutil/specification.html @@ -0,0 +1,351 @@ +<html> +<!-- + - The contents of this file are subject to the Mozilla Public + - License Version 1.1 (the "License"); you may not use this file + - except in compliance with the License. You may obtain a copy of + - the License at http://www.mozilla.org/MPL/ + - + - Software distributed under the License is distributed on an "AS + - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + - implied. See the License for the specific language governing + - rights and limitations under 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. + --> +<head> +<title>Modutil Specification</title> +</head> +<body bgcolor=white fgcolor=black> +<center><h1>PKCS #11 Module Management Utility +<br><i>Specification</i></h1></center> + +<!----------------------------------------------------------------------> +<!-------------------------- capabilities ------------------------------> +<!----------------------------------------------------------------------> +<h2>Capabilities</h2> +<ul> +<li>Add a PKCS #11 module, specifying a name and library file. +(<a href="#add">-add</a>) +<li>Add a PKCS #11 module from a server-formatted JAR file. +(<a href="#jar">-jar</a>) +<li>Change the password on or initialize a token. +(<a href="#changepw">-changepw</a>) +<li>Create databases (secmod[ule].db, key3.db, cert7.db) from scratch. +(<a href="#create">-create</a>) +<li>Switch to and from FIPS-140-1 compliant mode. +(<a href="#fips">-fips</a>) +<li>Delete a PKCS #11 module. (<a href="#delete">-delete</a>) +<li>List installed PKCS #11 modules. (<a href="#list">-list</a>) +<li>List detailed info on a particular module and its tokens, including +whether needs login, is hardware, needs user init +(<a href="#list">-list</a>) +<li>Specify which modules should be the default provider of various +cryptographic operations.(<a href="#default">-default</a>, +<a href="#undefault">-undefault</a>) +<li>Disable and enable slots, find out whether and why they are disabled. +(<a href="#disable">-disable</a>, <a href="#enable">-enable</a>, +<a href="#list">-list</a>) +</ul> + +<hr> + +<!----------------------------------------------------------------------> +<!-------------------------- Usage -------------------------------------> +<!----------------------------------------------------------------------> +<h2>Usage</h2> +<code>modutil [<i>command</i>] [<i>options</i>]</code> +<p>At most one command can be specified. With no arguments, +<code>modutil</code> prints a usage message. +<h3>Commands:</h3> +<table border> +<tr bgcolor="#cccccc"> +<th>Command</th><th>Description</th> +</tr> + +<!---------------------------- -add ------------------------------> +<tr> +<td> <a name="add"></a> +<code>-add <u><i>module name</i></u> -libfile <u><i>library file</i></u> + [-ciphers <u><i>cipher enable list</i></u>] + [-mechanisms <u><i>default mechanism list</i></u>] +</code></td> +<td>Adds a new module to the database with the given name. + +<p><u><i>library file</i></u> is the path of the DLL or other library file +containing the module's implementation of the PKCS #11 interface. + +<p><u><i>cipher enable flags</i></u> is a colon-separated list of ciphers +that will be enabled on this module. The list should be enclosed within quotes +if necessary to prevent shell interpretation. The following ciphers are +currently available: +<ul> +<li>FORTEZZA +</ul> + +<p><u><i>default mechanism flags</i></u> is a colon-separated list of +mechanisms for which this module should be the default provider. The +list should be enclosed within quotes if necessary to prevent shell +interpretation. <b>This +list does not enable the mechanisms; it only specifies that this module +will be a default provider for the listed mechanisms.</b> If more than +one module claims to be a default provider for a given mechanism, it is +undefined which will actually be chosen to provide that mechanism. The +following mechanisms are currently available: +<ul> +<li>RSA +<li>DSA +<li>RC2 +<li>RC4 +<li>RC5 +<li>DES +<li>DH +<li>FORTEZZA +<li>SHA1 +<li>MD5 +<li>MD2 +<li>RANDOM <i>(random number generation)</i> +<li>FRIENDLY <i>(certificates are publicly-readable)</i> +</ul> +</td> +</tr> + +<!-------------------------- -changepw -------------------------------------> +<tr> +<td><a name="changepw"></a><code>-changepw <u><i>token name</i></u> +[-pwfile <u><i>old password file</i></u>] +[-newpwfile <u><i>new password file</i></u>]</code></td> +<td>Changes the password on the named token. If the token has not been +initialized, this command will initialize the PIN. +If a password file is given, the password will be read from that file; +otherwise, the password will be obtained interactively. +<b>Storing passwords in a file is much less secure than supplying them +interactively.</b> +<p>The password on the Netscape internal module cannot be changed if +the <code>-nocertdb</code> option is specified. +</td> +</tr> + +<!-------------------------- -create -------------------------------------> +<tr> +<td><a name="create"></a><code>-create</code></td> +<td>Creates a new secmod[ule].db, key3.db, and cert7.db in the directory +specified with the +<code>-dbdir</code> option, if one is specified. If no directory is +specified, UNIX systems will use the user's .netscape directory, while other +systems will return with an error message. If any of these databases already +exist in the chosen directory, an error message is returned. +<p>If used with <code>-nocertdb</code>, only secmod[ule].db will be created; +cert7.db and key3.db will not be created. +</td> +</tr> + +<!------------------------------ -default --------------------------------> +<tr> +<td> <a name="default"></a> <code>-default <u><i>module name</i></u> +-mechanisms <u><i>mechanism list</i></u></code> +</td> +<td>Specifies that the given module will be a default provider of the +listed mechanisms. The mechanism list is the same as in the <code>-add</code> +command. +</td> +</tr> + +<!-------------------------- -delete -------------------------------------> +<tr> +<td><a name="delete"></a><code>-delete <u><i>module name</i></u></code></td> +<td>Deletes the named module from the database</td> +</tr> + +<!-------------------------- -disable -------------------------------------> +<tr> +<td> <a name="disable"></a> <code>-disable <u><i>module name</i></u> +[-slot <u><i>slot name</i></u>]</code></td> +<td>Disables the named slot. If no slot is specified, all slots on +the module are disabled.</td> +</tr> + +<!-------------------------- -enable -------------------------------------> +<tr> +<td> <a name="enable"></a> <code>-enable <u><i>module name</i></u> +[-slot <u><i>slot name</i></u>]</code></td> +<td>Enables the named slot. If no slot is specified, all slots on +the module are enabled.</td> +</tr> + +<!-------------------------- -fips -------------------------------------> +<tr> +<td><a name="fips"></a><code>-fips [true | false]</code></td> +<td>Enables or disables FIPS mode on the internal module. Passing +<code>true</code> enables FIPS mode, passing <code>false</code> disables +FIPS mode.</td> +</tr> + +<!-------------------------- -force -------------------------------------> +<tr> +<td><a name="force"></a><code>-force</code></td> +<td>Disables interactive prompts, so modutil can be run in a script. +Should only be used by experts, since the prompts may relate to security +or database integrity. Before using this option, test the command +interactively once to see the warnings that are produced.</td> +</tr> + +<!-------------------------- -jar -------------------------------------> +<tr> +<td><a name="jar"></a><code>-jar <u><i>JAR file</i></u> +-installdir <u><i>root installation directory</i></u> +[-tempdir <u><i>temporary directory</i></u>]</code></td> +<td>Adds a new module from the given JAR file. The JAR file uses the +server <a href="pk11jar.html">PKCS #11 JAR format</a> to describe the names of +any files that need to be installed, the name of the module, mechanism flags, +and cipher flags. The <u><i>root installation directory</i></u> +is the directory relative to which files will be installed. This should be a + directory +under which it would be natural to store dynamic library files, such as +a server's root directory, or Communicator's root directory. +The <u><i>temporary directory</i></u> is where temporary modutil files +will be created in the course of the installation. If no temporary directory +is specified, the current directory will be used. +<p>If used with the <code>-nocertdb</code> option, the signatures on the JAR +file will not be checked.</td> +</tr> + +<!----------------------------- -list ------------------------------> +<tr> +<td><a name="list"></a><code>-list [<u><i>module name</i></u>]</code></td> +<td>Without an argument, lists the PKCS #11 modules present in the module +database. +<blockquote> +<pre> +% <b>modutil -list</b> +Using database directory /u/nicolson/.netscape... + +Listing of PKCS #11 Modules +----------------------------------------------------------- + 1. Netscape Internal PKCS #11 Module + slots: 2 slots attached + status: loaded + + slot: Communicator Internal Cryptographic Services Version 4.0 + token: Communicator Generic Crypto Svcs + + slot: Communicator User Private Key and Certificate Services + token: Communicator Certificate DB +----------------------------------------------------------- +</pre> +</blockquote> +<p>With an argument, provides a detailed description of the named module +and its slots and tokens. +<blockquote> +<pre> +% <b>modutil -list "Netscape Internal PKCS #11 Module"</b> +Using database directory /u/nicolson/.netscape... + +----------------------------------------------------------- +Name: Netscape Internal PKCS #11 Module +Library file: **Internal ONLY module** +Manufacturer: Netscape Communications Corp +Description: Communicator Internal Crypto Svc +PKCS #11 Version 2.0 +Library Version: 4.0 +Cipher Enable Flags: None +Default Mechanism Flags: RSA:DSA:RC2:RC4:DES:SHA1:MD5:MD2 + + Slot: Communicator Internal Cryptographic Services Version 4.0 + Manufacturer: Netscape Communications Corp + Type: Software + Version Number: 4.1 + Firmware Version: 0.0 + Status: Enabled + Token Name: Communicator Generic Crypto Svcs + Token Manufacturer: Netscape Communications Corp + Token Model: Libsec 4.0 + Token Serial Number: 0000000000000000 + Token Version: 4.0 + Token Firmware Version: 0.0 + Access: Write Protected + Login Type: Public (no login required) + User Pin: NOT Initialized + + Slot: Communicator User Private Key and Certificate Services + Manufacturer: Netscape Communications Corp + Type: Software + Version Number: 3.0 + Firmware Version: 0.0 + Status: Enabled + Token Name: Communicator Certificate DB + Token Manufacturer: Netscape Communications Corp + Token Model: Libsec 4.0 + Token Serial Number: 0000000000000000 + Token Version: 7.0 + Token Firmware Version: 0.0 + Access: NOT Write Protected + Login Type: Login required + User Pin: Initialized + +----------------------------------------------------------- +</pre> +</blockquote> +</td> +</tr> + +<!------------------------------ Undefault -------------------------------> +<tr> +<td><a name="undefault"></a><code>-undefault <u><i>module name</i></u> +-mechanisms <u><i>mechanism list</i></u></code></td> +<td>Specifies that the given module will NOT be a default provider of +the listed mechanisms. This command clears the default mechanism flags +for the given module.</td> +</tr> + +</table> + +<!------------------------------------------------------------------------> +<!------------------------------ Options ---------------------------------> +<!------------------------------------------------------------------------> +<h3>Options:</h3> +<table border> +<tr bgcolor="#cccccc"><th>Option</th><th>Description</th> </tr> + +<!------------------------------ -dbdir ----------------------------------> +<tr> +<td><code>-dbdir <u><i>directory</i></u></code></td> +<td>Specifies which directory holds the module database. On UNIX systems, +the user's netscape directory is the default. On other systems, there is +no default, and this option must be used.</td> +</tr> + +<!------------------------------ -dbdir ----------------------------------> +<tr> +<td><code>-nocertdb</code></td> +<td>Do not open the certificate or key databases. This has several effects. +With the <code>-create</code> command, this means that only a secmod.db file +will be created; cert7.db and key3.db will not be created. With the +<code>-jar</code> command, signatures on the JAR file will not be checked. +With the <code>-changepw</code> command, the password on the Netscape internal +module cannot be set or changed, since this password is stored in key3.db. +</td> +</tr> + +</table> + +</body> +</html> diff --git a/security/nss/cmd/ocspclnt/Makefile b/security/nss/cmd/ocspclnt/Makefile new file mode 100644 index 000000000..490f738e5 --- /dev/null +++ b/security/nss/cmd/ocspclnt/Makefile @@ -0,0 +1,73 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk diff --git a/security/nss/cmd/ocspclnt/manifest.mn b/security/nss/cmd/ocspclnt/manifest.mn new file mode 100644 index 000000000..68a84b8c7 --- /dev/null +++ b/security/nss/cmd/ocspclnt/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +CSRCS = \ + ocspclnt.c \ + $(NULL) + +# headers for the MODULE (defined above) are implicitly required. +REQUIRES = dbm seccmd + +# WINNT uses EXTRA_LIBS as the list of libs to link in. +# Unix uses OS_LIBS for that purpose. +# We can solve this via conditional makefile code, but +# can't do this in manifest.mn because OS_ARCH isn't defined there. +# So, look in the local Makefile for the defines for the list of libs. + +PROGRAM = ocspclnt + +USE_STATIC_LIBS = 1 diff --git a/security/nss/cmd/ocspclnt/ocspclnt.c b/security/nss/cmd/ocspclnt/ocspclnt.c new file mode 100644 index 000000000..309d08538 --- /dev/null +++ b/security/nss/cmd/ocspclnt/ocspclnt.c @@ -0,0 +1,1221 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* + * Test program for client-side OCSP. + * + * $Id$ + */ + +#include "secutil.h" +#include "nspr.h" +#include "plgetopt.h" +#include "nss.h" +#include "cert.h" +#include "ocsp.h" +#include "xconst.h" /* + * XXX internal header file; needed to get at + * cert_DecodeAuthInfoAccessExtension -- would be + * nice to not need this, but that would require + * better/different APIs. + */ + +#ifndef NO_PP /* + * Compile with this every once in a while to be + * sure that no dependencies on it get added + * outside of the pretty-printing routines. + */ +#include "ocspti.h" /* internals for pretty-printing routines *only* */ +#endif /* NO_PP */ + +#define DEFAULT_DB_DIR "~/.netscape" + + +static void +synopsis (char *program_name) +{ + PRFileDesc *pr_stderr; + + pr_stderr = PR_STDERR; + PR_fprintf (pr_stderr, "Usage:"); + PR_fprintf (pr_stderr, + "\t%s -p [-d <dir>]\n", + program_name); + PR_fprintf (pr_stderr, + "\t%s -P [-d <dir>]\n", + program_name); + PR_fprintf (pr_stderr, + "\t%s -r <name> [-L] [-s <name>] [-d <dir>]\n", + program_name); + PR_fprintf (pr_stderr, + "\t%s -R <name> [-l <location>] [-s <name>] [-d <dir>]\n", + program_name); + PR_fprintf (pr_stderr, + "\t%s -S <name> [-l <location> -t <name>]\n", + program_name); + PR_fprintf (pr_stderr, + "\t\t [-s <name>] [-w <time>] [-d <dir>]\n"); + PR_fprintf (pr_stderr, + "\t%s -V <name> -u <usage> [-l <location> -t <name>]\n", + program_name); + PR_fprintf (pr_stderr, + "\t\t [-s <name>] [-w <time>] [-d <dir>]\n"); +} + + +static void +short_usage (char *program_name) +{ + PR_fprintf (PR_STDERR, + "Type %s -H for more detailed descriptions\n", + program_name); + synopsis (program_name); +} + + +static void +long_usage (char *program_name) +{ + PRFileDesc *pr_stderr; + + pr_stderr = PR_STDERR; + synopsis (program_name); + PR_fprintf (pr_stderr, "\nCommands (must specify exactly one):\n"); + PR_fprintf (pr_stderr, + " %-13s Pretty-print a binary request read from stdin\n", + "-p"); + PR_fprintf (pr_stderr, + " %-13s Pretty-print a binary response read from stdin\n", + "-P"); + PR_fprintf (pr_stderr, + " %-13s Create a request for cert \"nickname\" on stdout\n", + "-r nickname"); + PR_fprintf (pr_stderr, + " %-13s Get response for cert \"nickname\", dump to stdout\n", + "-R nickname"); + PR_fprintf (pr_stderr, + " %-13s Get status for cert \"nickname\"\n", + "-S nickname"); + PR_fprintf (pr_stderr, + " %-13s Fully verify cert \"nickname\", w/ status check\n", + "-V nickname"); + PR_fprintf (pr_stderr, "Options:\n"); + PR_fprintf (pr_stderr, + " %-13s Add the service locator extension to the request\n", + "-L"); + PR_fprintf (pr_stderr, + " %-13s Find security databases in \"dbdir\" (default %s)\n", + "-d dbdir", DEFAULT_DB_DIR); + PR_fprintf (pr_stderr, + " %-13s Use \"location\" as URL of responder\n", + "-l location"); + PR_fprintf (pr_stderr, + " %-13s Trust cert \"nickname\" as response signer\n", + "-t nickname"); + PR_fprintf (pr_stderr, + " %-13s Sign requests with cert \"nickname\"\n", + "-s nickname"); + PR_fprintf (pr_stderr, + " %-13s Type of certificate usage for verification:\n", + "-u usage"); + PR_fprintf (pr_stderr, + "%-17s c SSL Client\n", ""); + PR_fprintf (pr_stderr, + "%-17s s SSL Server\n", ""); + PR_fprintf (pr_stderr, + "%-17s e Email Recipient\n", ""); + PR_fprintf (pr_stderr, + "%-17s E Email Signer\n", ""); + PR_fprintf (pr_stderr, + "%-17s S Object Signer\n", ""); + PR_fprintf (pr_stderr, + "%-17s C CA\n", ""); + PR_fprintf (pr_stderr, + " %-13s Validity time (default current time), one of:\n", + "-w time"); + PR_fprintf (pr_stderr, + "%-17s %-25s (GMT)\n", "", "YYMMDDhhmm[ss]Z"); + PR_fprintf (pr_stderr, + "%-17s %-25s (later than GMT)\n", "", "YYMMDDhhmm[ss]+hhmm"); + PR_fprintf (pr_stderr, + "%-17s %-25s (earlier than GMT)\n", "", "YYMMDDhhmm[ss]-hhmm"); +} + + +/* + * XXX This is a generic function that would probably make a good + * replacement for SECU_DER_Read (which is not at all specific to DER, + * despite its name), but that requires fixing all of the tools... + * Still, it should be done, whenenver I/somebody has the time. + * (Also, consider whether this actually belongs in the security + * library itself, not just in the command library.) + * + * This function takes an open file (a PRFileDesc *) and reads the + * entire file into a SECItem. (Obviously, the file is intended to + * be small enough that such a thing is advisable.) Both the SECItem + * and the buffer it points to are allocated from the heap; the caller + * is expected to free them. ("SECITEM_FreeItem(item, PR_TRUE)") + */ +static SECItem * +read_file_into_item (PRFileDesc *in_file, SECItemType si_type) +{ + PRStatus prv; + SECItem *item; + PRFileInfo file_info; + PRInt32 bytes_read; + + prv = PR_GetOpenFileInfo (in_file, &file_info); + if (prv != PR_SUCCESS) + return NULL; + + if (file_info.size == 0) { + /* XXX Need a better error; just grabbed this one for expediency. */ + PORT_SetError (SEC_ERROR_INPUT_LEN); + return NULL; + } + + if (file_info.size > 0xffff) { /* I think this is too big. */ + PORT_SetError (SEC_ERROR_NO_MEMORY); + return NULL; + } + + item = PORT_Alloc (sizeof (SECItem)); + if (item == NULL) + return NULL; + + item->type = si_type; + item->len = (unsigned int) file_info.size; + item->data = PORT_Alloc ((size_t)item->len); + if (item->data == NULL) + goto loser; + + bytes_read = PR_Read (in_file, item->data, (PRInt32) item->len); + if (bytes_read < 0) { + /* Something went wrong; error is already set for us. */ + goto loser; + } else if (bytes_read == 0) { + /* Something went wrong; we read nothing. But no system/nspr error. */ + /* XXX Need to set an error here. */ + goto loser; + } else if (item->len != (unsigned int)bytes_read) { + /* Something went wrong; we read less (or more!?) than we expected. */ + /* XXX Need to set an error here. */ + goto loser; + } + + return item; + +loser: + SECITEM_FreeItem (item, PR_TRUE); + return NULL; +} + + +/* + * Create a DER-encoded OCSP request (for the certificate whose nickname + * is "name") and dump it out. + */ +static SECStatus +create_request (FILE *out_file, CERTCertDBHandle *handle, const char *cert_name, + PRBool add_service_locator, PRBool add_acceptable_responses) +{ + CERTCertificate *cert = NULL; + CERTCertList *certs = NULL; + CERTOCSPRequest *request = NULL; + int64 now = PR_Now(); + SECItem *encoding = NULL; + SECStatus rv = SECFailure; + + if (handle == NULL || cert_name == NULL) + goto loser; + + cert = CERT_FindCertByNicknameOrEmailAddr (handle, (char *) cert_name); + if (cert == NULL) + goto loser; + + /* + * We need to create a list of one. + */ + certs = CERT_NewCertList(); + if (certs == NULL) + goto loser; + + if (CERT_AddCertToListTail (certs, cert) != SECSuccess) + goto loser; + + /* + * Now that cert is included in the list, we need to be careful + * that we do not try to destroy it twice. This will prevent that. + */ + cert = NULL; + + request = CERT_CreateOCSPRequest (certs, now, add_service_locator, NULL); + if (request == NULL) + goto loser; + + if (add_acceptable_responses) { + rv = CERT_AddOCSPAcceptableResponses(request, + SEC_OID_PKIX_OCSP_BASIC_RESPONSE); + if (rv != SECSuccess) + goto loser; + } + + encoding = CERT_EncodeOCSPRequest (NULL, request, NULL); + if (encoding == NULL) + goto loser; + + if (fwrite (encoding->data, encoding->len, 1, out_file) != 1) + goto loser; + + rv = SECSuccess; + +loser: + if (encoding != NULL) + SECITEM_FreeItem(encoding, PR_TRUE); + if (request != NULL) + CERT_DestroyOCSPRequest(request); + if (certs != NULL) + CERT_DestroyCertList (certs); + if (cert != NULL) + CERT_DestroyCertificate (cert); + + return rv; +} + + +/* + * Create a DER-encoded OCSP request (for the certificate whose nickname is + * "cert_name"), then get and dump a corresponding response. The responder + * location is either specified explicitly (as "responder_url") or found + * via the AuthorityInfoAccess URL in the cert. + */ +static SECStatus +dump_response (FILE *out_file, CERTCertDBHandle *handle, const char *cert_name, + const char *responder_url) +{ + CERTCertificate *cert = NULL; + CERTCertList *certs = NULL; + char *loc = NULL; + int64 now = PR_Now(); + SECItem *response = NULL; + SECStatus rv = SECFailure; + PRBool includeServiceLocator; + + if (handle == NULL || cert_name == NULL) + goto loser; + + cert = CERT_FindCertByNicknameOrEmailAddr (handle, (char *) cert_name); + if (cert == NULL) + goto loser; + + if (responder_url != NULL) { + loc = (char *) responder_url; + includeServiceLocator = PR_TRUE; + } else { + loc = CERT_GetOCSPAuthorityInfoAccessLocation (cert); + if (loc == NULL) + goto loser; + includeServiceLocator = PR_FALSE; + } + + /* + * We need to create a list of one. + */ + certs = CERT_NewCertList(); + if (certs == NULL) + goto loser; + + if (CERT_AddCertToListTail (certs, cert) != SECSuccess) + goto loser; + + /* + * Now that cert is included in the list, we need to be careful + * that we do not try to destroy it twice. This will prevent that. + */ + cert = NULL; + + response = CERT_GetEncodedOCSPResponse (NULL, certs, loc, now, + includeServiceLocator, + NULL, NULL, NULL); + if (response == NULL) + goto loser; + + if (fwrite (response->data, response->len, 1, out_file) != 1) + goto loser; + + rv = SECSuccess; + +loser: + if (response != NULL) + SECITEM_FreeItem (response, PR_TRUE); + if (certs != NULL) + CERT_DestroyCertList (certs); + if (loc != NULL && loc != responder_url) + PORT_Free (loc); + if (cert != NULL) + CERT_DestroyCertificate (cert); + + return rv; +} + + +/* + * Get the status for the specified certificate (whose nickname is "cert_name"). + * Directly use the OCSP function rather than doing a full verification. + */ +static SECStatus +get_cert_status (FILE *out_file, CERTCertDBHandle *handle, + const char *cert_name, int64 verify_time) +{ + CERTCertificate *cert = NULL; + SECStatus rv = SECFailure; + + if (handle == NULL || cert_name == NULL) + goto loser; + + cert = CERT_FindCertByNicknameOrEmailAddr (handle, (char *) cert_name); + if (cert == NULL) + goto loser; + + rv = CERT_CheckOCSPStatus (handle, cert, verify_time, NULL); + + fprintf (out_file, "Check of certificate \"%s\" ", cert_name); + if (rv == SECSuccess) { + fprintf (out_file, "succeeded.\n"); + } else { + const char *error_string = SECU_Strerror(PORT_GetError()); + fprintf (out_file, "failed. Reason:\n"); + if (error_string != NULL && PORT_Strlen(error_string) > 0) + fprintf (out_file, "%s\n", error_string); + else + fprintf (out_file, "Unknown\n"); + } + + rv = SECSuccess; + +loser: + if (cert != NULL) + CERT_DestroyCertificate (cert); + + return rv; +} + + +/* + * Verify the specified certificate (whose nickname is "cert_name"). + * OCSP is already turned on, so we just need to call the standard + * certificate verification API and let it do all the work. + */ +static SECStatus +verify_cert (FILE *out_file, CERTCertDBHandle *handle, const char *cert_name, + SECCertUsage cert_usage, int64 verify_time) +{ + CERTCertificate *cert = NULL; + SECStatus rv = SECFailure; + + if (handle == NULL || cert_name == NULL) + goto loser; + + cert = CERT_FindCertByNicknameOrEmailAddr (handle, (char *) cert_name); + if (cert == NULL) + goto loser; + + rv = CERT_VerifyCert (handle, cert, PR_TRUE, cert_usage, verify_time, + NULL, NULL); + + fprintf (out_file, "Verification of certificate \"%s\" ", cert_name); + if (rv == SECSuccess) { + fprintf (out_file, "succeeded.\n"); + } else { + const char *error_string = SECU_Strerror(PORT_GetError()); + fprintf (out_file, "failed. Reason:\n"); + if (error_string != NULL && PORT_Strlen(error_string) > 0) + fprintf (out_file, "%s\n", error_string); + else + fprintf (out_file, "Unknown\n"); + } + + rv = SECSuccess; + +loser: + if (cert != NULL) + CERT_DestroyCertificate (cert); + + return rv; +} + + +#ifdef NO_PP + +static SECStatus +print_request (FILE *out_file, SECItem *data) +{ + fprintf (out_file, "Cannot pretty-print request compiled with NO_PP.\n"); + return SECSuccess; +} + +static SECStatus +print_response (FILE *out_file, SECItem *data, CERTCertDBHandle *handle) +{ + fprintf (out_file, "Cannot pretty-print response compiled with NO_PP.\n"); + return SECSuccess; +} + +#else /* NO_PP */ + +static void +print_ocsp_version (FILE *out_file, SECItem *version, int level) +{ + if (version->len > 0) { + SECU_PrintInteger (out_file, version, "Version", level); + } else { + SECU_Indent (out_file, level); + fprintf (out_file, "Version: DEFAULT\n"); + } +} + + +static void +print_ocsp_cert_id (FILE *out_file, CERTOCSPCertID *cert_id, int level) +{ + SECU_Indent (out_file, level); + fprintf (out_file, "Cert ID:\n"); + level++; + + SECU_PrintAlgorithmID (out_file, &(cert_id->hashAlgorithm), + "Hash Algorithm", level); + SECU_PrintAsHex (out_file, &(cert_id->issuerNameHash), + "Issuer Name Hash", level); + SECU_PrintAsHex (out_file, &(cert_id->issuerKeyHash), + "Issuer Key Hash", level); + SECU_PrintInteger (out_file, &(cert_id->serialNumber), + "Serial Number", level); + /* XXX lookup the cert; if found, print something nice (nickname?) */ +} + + +static void +print_raw_certificates (FILE *out_file, SECItem **raw_certs, int level) +{ + SECItem *raw_cert; + int i = 0; + char cert_label[50]; + + SECU_Indent (out_file, level); + + if (raw_certs == NULL) { + fprintf (out_file, "No Certificates.\n"); + return; + } + + fprintf (out_file, "Certificate List:\n"); + while ((raw_cert = raw_certs[i++]) != NULL) { + sprintf (cert_label, "Certificate (%d)", i); + (void) SECU_PrintSignedData (out_file, raw_cert, cert_label, level + 1, + SECU_PrintCertificate); + } +} + + +static void +print_ocsp_extensions (FILE *out_file, CERTCertExtension **extensions, + char *msg, int level) +{ + if (extensions) { + SECU_PrintExtensions (out_file, extensions, msg, level); + } else { + SECU_Indent (out_file, level); + fprintf (out_file, "No %s\n", msg); + } +} + + +static void +print_single_request (FILE *out_file, ocspSingleRequest *single, int level) +{ + print_ocsp_cert_id (out_file, single->reqCert, level); + print_ocsp_extensions (out_file, single->singleRequestExtensions, + "Single Request Extensions", level); +} + + +/* + * Decode the DER/BER-encoded item "data" as an OCSP request + * and pretty-print the subfields. + */ +static SECStatus +print_request (FILE *out_file, SECItem *data) +{ + CERTOCSPRequest *request; + ocspTBSRequest *tbsRequest; + int level = 0; + + PORT_Assert (out_file != NULL); + PORT_Assert (data != NULL); + if (out_file == NULL || data == NULL) { + PORT_SetError (SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + request = CERT_DecodeOCSPRequest (data); + if (request == NULL || request->tbsRequest == NULL) + return SECFailure; + + tbsRequest = request->tbsRequest; + + fprintf (out_file, "TBS Request:\n"); + level++; + + print_ocsp_version (out_file, &(tbsRequest->version), level); + + /* + * XXX Probably should be an interface to get the signer name + * without looking inside the tbsRequest at all. + */ + if (tbsRequest->requestorName != NULL) { + SECU_Indent (out_file, level); + fprintf (out_file, "XXX print the requestorName\n"); + } else { + SECU_Indent (out_file, level); + fprintf (out_file, "No Requestor Name.\n"); + } + + if (tbsRequest->requestList != NULL) { + int i; + + for (i = 0; tbsRequest->requestList[i] != NULL; i++) { + SECU_Indent (out_file, level); + fprintf (out_file, "Request %d:\n", i); + print_single_request (out_file, tbsRequest->requestList[i], + level + 1); + } + } else { + fprintf (out_file, "Request list is empty.\n"); + } + + print_ocsp_extensions (out_file, tbsRequest->requestExtensions, + "Request Extensions", level); + + if (request->optionalSignature != NULL) { + ocspSignature *whole_sig; + SECItem rawsig; + + fprintf (out_file, "Signature:\n"); + + whole_sig = request->optionalSignature; + SECU_PrintAlgorithmID (out_file, &(whole_sig->signatureAlgorithm), + "Signature Algorithm", level); + + rawsig = whole_sig->signature; + DER_ConvertBitString (&rawsig); + SECU_PrintAsHex (out_file, &rawsig, "Signature", level); + + print_raw_certificates (out_file, whole_sig->derCerts, level); + + fprintf (out_file, "XXX verify the sig and print result\n"); + } else { + fprintf (out_file, "No Signature\n"); + } + + CERT_DestroyOCSPRequest (request); + return SECSuccess; +} + + +static void +print_revoked_info (FILE *out_file, ocspRevokedInfo *revoked_info, int level) +{ + SECU_PrintGeneralizedTime (out_file, &(revoked_info->revocationTime), + "Revocation Time", level); + + if (revoked_info->revocationReason != NULL) { + SECU_PrintAsHex (out_file, revoked_info->revocationReason, + "Revocation Reason", level); + } else { + SECU_Indent (out_file, level); + fprintf (out_file, "No Revocation Reason.\n"); + } +} + + +static void +print_cert_status (FILE *out_file, ocspCertStatus *status, int level) +{ + SECU_Indent (out_file, level); + fprintf (out_file, "Status: "); + + switch (status->certStatusType) { + case ocspCertStatus_good: + fprintf (out_file, "Cert is good.\n"); + break; + case ocspCertStatus_revoked: + fprintf (out_file, "Cert has been revoked.\n"); + print_revoked_info (out_file, status->certStatusInfo.revokedInfo, + level + 1); + break; + case ocspCertStatus_unknown: + fprintf (out_file, "Cert is unknown to responder.\n"); + break; + default: + fprintf (out_file, "Unrecognized status.\n"); + break; + } +} + + +static void +print_single_response (FILE *out_file, CERTOCSPSingleResponse *single, + int level) +{ + print_ocsp_cert_id (out_file, single->certID, level); + + print_cert_status (out_file, single->certStatus, level); + + SECU_PrintGeneralizedTime (out_file, &(single->thisUpdate), + "This Update", level); + + if (single->nextUpdate != NULL) { + SECU_PrintGeneralizedTime (out_file, single->nextUpdate, + "Next Update", level); + } else { + SECU_Indent (out_file, level); + fprintf (out_file, "No Next Update\n"); + } + + print_ocsp_extensions (out_file, single->singleExtensions, + "Single Response Extensions", level); +} + + +static void +print_responder_id (FILE *out_file, ocspResponderID *responderID, int level) +{ + SECU_Indent (out_file, level); + fprintf (out_file, "Responder ID "); + + switch (responderID->responderIDType) { + case ocspResponderID_byName: + fprintf (out_file, "(byName):\n"); + SECU_PrintName (out_file, &(responderID->responderIDValue.name), + "Name", level + 1); + break; + case ocspResponderID_byKey: + fprintf (out_file, "(byKey):\n"); + SECU_PrintAsHex (out_file, &(responderID->responderIDValue.keyHash), + "Key Hash", level + 1); + break; + default: + fprintf (out_file, "Unrecognized Responder ID Type\n"); + break; + } +} + + +static void +print_response_data (FILE *out_file, ocspResponseData *responseData, int level) +{ + SECU_Indent (out_file, level); + fprintf (out_file, "Response Data:\n"); + level++; + + print_ocsp_version (out_file, &(responseData->version), level); + + print_responder_id (out_file, responseData->responderID, level); + + SECU_PrintGeneralizedTime (out_file, &(responseData->producedAt), + "Produced At", level); + + if (responseData->responses != NULL) { + int i; + + for (i = 0; responseData->responses[i] != NULL; i++) { + SECU_Indent (out_file, level); + fprintf (out_file, "Response %d:\n", i); + print_single_response (out_file, responseData->responses[i], + level + 1); + } + } else { + fprintf (out_file, "Response list is empty.\n"); + } + + print_ocsp_extensions (out_file, responseData->responseExtensions, + "Response Extensions", level); +} + + +static void +print_basic_response (FILE *out_file, ocspBasicOCSPResponse *basic, int level) +{ + SECItem rawsig; + + SECU_Indent (out_file, level); + fprintf (out_file, "Basic OCSP Response:\n"); + level++; + + print_response_data (out_file, basic->tbsResponseData, level); + + SECU_PrintAlgorithmID (out_file, + &(basic->responseSignature.signatureAlgorithm), + "Signature Algorithm", level); + + rawsig = basic->responseSignature.signature; + DER_ConvertBitString (&rawsig); + SECU_PrintAsHex (out_file, &rawsig, "Signature", level); + + print_raw_certificates (out_file, basic->responseSignature.derCerts, level); +} + + +/* + * Note this must match (exactly) the enumeration ocspResponseStatus. + */ +static char *responseStatusNames[] = { + "successful (Response has valid confirmations)", + "malformedRequest (Illegal confirmation request)", + "internalError (Internal error in issuer)", + "tryLater (Try again later)", + "unused ((4) is not used)", + "sigRequired (Must sign the request)", + "unauthorized (Request unauthorized)", + "other (Status value out of defined range)" +}; + +/* + * Decode the DER/BER-encoded item "data" as an OCSP response + * and pretty-print the subfields. + */ +static SECStatus +print_response (FILE *out_file, SECItem *data, CERTCertDBHandle *handle) +{ + CERTOCSPResponse *response; + int level = 0; + + PORT_Assert (out_file != NULL); + PORT_Assert (data != NULL); + if (out_file == NULL || data == NULL) { + PORT_SetError (SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + response = CERT_DecodeOCSPResponse (data); + if (response == NULL) + return SECFailure; + + PORT_Assert (response->statusValue <= ocspResponse_other); + fprintf (out_file, "Response Status: %s\n", + responseStatusNames[response->statusValue]); + + if (response->statusValue == ocspResponse_successful) { + ocspResponseBytes *responseBytes = response->responseBytes; + SECStatus sigStatus; + CERTCertificate *signerCert = NULL; + + PORT_Assert (responseBytes != NULL); + + level++; + fprintf (out_file, "Response Bytes:\n"); + SECU_PrintObjectID (out_file, &(responseBytes->responseType), + "Response Type", level); + switch (response->responseBytes->responseTypeTag) { + case SEC_OID_PKIX_OCSP_BASIC_RESPONSE: + print_basic_response (out_file, + responseBytes->decodedResponse.basic, + level); + break; + default: + SECU_Indent (out_file, level); + fprintf (out_file, "Unknown response syntax\n"); + break; + } + + sigStatus = CERT_VerifyOCSPResponseSignature (response, handle, + NULL, &signerCert, NULL); + SECU_Indent (out_file, level); + fprintf (out_file, "Signature verification "); + if (sigStatus != SECSuccess) { + fprintf (out_file, "failed: %s\n", SECU_Strerror (PORT_GetError())); + } else { + fprintf (out_file, "succeeded.\n"); + if (signerCert != NULL) { + SECU_PrintName (out_file, &signerCert->subject, "Signer", + level); + CERT_DestroyCertificate (signerCert); + } else { + SECU_Indent (out_file, level); + fprintf (out_file, "No signer cert returned?\n"); + } + } + } else { + SECU_Indent (out_file, level); + fprintf (out_file, "Unsuccessful response, no more information.\n"); + } + + CERT_DestroyOCSPResponse (response); + return SECSuccess; +} + +#endif /* NO_PP */ + + +static SECStatus +cert_usage_from_char (const char *cert_usage_str, SECCertUsage *cert_usage) +{ + PORT_Assert (cert_usage_str != NULL); + PORT_Assert (cert_usage != NULL); + + if (PORT_Strlen (cert_usage_str) != 1) + return SECFailure; + + switch (*cert_usage_str) { + case 'c': + *cert_usage = certUsageSSLClient; + break; + case 's': + *cert_usage = certUsageSSLServer; + break; + case 'e': + *cert_usage = certUsageEmailRecipient; + break; + case 'E': + *cert_usage = certUsageEmailSigner; + break; + case 'S': + *cert_usage = certUsageObjectSigner; + break; + case 'C': + *cert_usage = certUsageVerifyCA; + break; + default: + return SECFailure; + } + + return SECSuccess; +} + + +int +main (int argc, char **argv) +{ + int retval; + char *program_name; + PRFileDesc *in_file; + FILE *out_file; /* not PRFileDesc until SECU accepts it */ + int crequest, dresponse; + int prequest, presponse; + int ccert, vcert; + const char *db_dir, *date_str, *cert_usage_str, *name; + const char *responder_name, *responder_url, *signer_name; + PRBool add_acceptable_responses, add_service_locator; + SECItem *data = NULL; + PLOptState *optstate; + SECStatus rv; + CERTCertDBHandle *handle = NULL; + SECCertUsage cert_usage; + int64 verify_time; + + retval = -1; /* what we return/exit with on error */ + + program_name = PL_strrchr(argv[0], '/'); + program_name = program_name ? (program_name + 1) : argv[0]; + + in_file = PR_STDIN; + out_file = stdout; + + crequest = 0; + dresponse = 0; + prequest = 0; + presponse = 0; + ccert = 0; + vcert = 0; + + db_dir = NULL; + date_str = NULL; + cert_usage_str = NULL; + name = NULL; + responder_name = NULL; + responder_url = NULL; + signer_name = NULL; + + add_acceptable_responses = PR_FALSE; + add_service_locator = PR_FALSE; + + optstate = PL_CreateOptState (argc, argv, "AHLPR:S:V:d:l:pr:s:t:u:w:"); + if (optstate == NULL) { + SECU_PrintError (program_name, "PL_CreateOptState failed"); + return retval; + } + + while (PL_GetNextOpt (optstate) == PL_OPT_OK) { + switch (optstate->option) { + case '?': + short_usage (program_name); + return retval; + + case 'A': + add_acceptable_responses = PR_TRUE; + break; + + case 'H': + long_usage (program_name); + return retval; + + case 'L': + add_service_locator = PR_TRUE; + break; + + case 'P': + presponse = 1; + break; + + case 'R': + dresponse = 1; + name = optstate->value; + break; + + case 'S': + ccert = 1; + name = optstate->value; + break; + + case 'V': + vcert = 1; + name = optstate->value; + break; + + case 'd': + db_dir = optstate->value; + break; + + case 'l': + responder_url = optstate->value; + break; + + case 'p': + prequest = 1; + break; + + case 'r': + crequest = 1; + name = optstate->value; + break; + + case 's': + signer_name = optstate->value; + break; + + case 't': + responder_name = optstate->value; + break; + + case 'u': + cert_usage_str = optstate->value; + break; + + case 'w': + date_str = optstate->value; + break; + } + } + + if ((crequest + dresponse + prequest + presponse + ccert + vcert) != 1) { + PR_fprintf (PR_STDERR, "%s: must specify exactly one command\n\n", + program_name); + short_usage (program_name); + return retval; + } + + if (vcert) { + if (cert_usage_str == NULL) { + PR_fprintf (PR_STDERR, "%s: verification requires cert usage\n\n", + program_name); + short_usage (program_name); + return retval; + } + + rv = cert_usage_from_char (cert_usage_str, &cert_usage); + if (rv != SECSuccess) { + PR_fprintf (PR_STDERR, "%s: invalid cert usage (\"%s\")\n\n", + program_name, cert_usage_str); + long_usage (program_name); + return retval; + } + } + + if (ccert + vcert) { + if (responder_url != NULL || responder_name != NULL) { + /* + * To do a full status check, both the URL and the cert name + * of the responder must be specified if either one is. + */ + if (responder_url == NULL || responder_name == NULL) { + if (responder_url == NULL) + PR_fprintf (PR_STDERR, + "%s: must also specify responder location\n\n", + program_name); + else + PR_fprintf (PR_STDERR, + "%s: must also specify responder name\n\n", + program_name); + short_usage (program_name); + return retval; + } + } + + if (date_str != NULL) { + rv = DER_AsciiToTime (&verify_time, (char *) date_str); + if (rv != SECSuccess) { + SECU_PrintError (program_name, "error converting time string"); + PR_fprintf (PR_STDERR, "\n"); + long_usage (program_name); + return retval; + } + } else { + verify_time = PR_Now(); + } + } + + retval = -2; /* errors change from usage to runtime */ + + /* + * Initialize the NSPR and Security libraries. + */ + PR_Init (PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + db_dir = SECU_ConfigDirectory (db_dir); + rv = NSS_Init (db_dir); + if (rv != SECSuccess) { + SECU_PrintError (program_name, "NSS_Init failed"); + goto prdone; + } + + if (prequest + presponse) { + data = read_file_into_item (in_file, siBuffer); + if (data == NULL) { + SECU_PrintError (program_name, "problem reading input"); + goto nssdone; + } + } + + if (crequest + dresponse + presponse + ccert + vcert) { + handle = CERT_GetDefaultCertDB(); + if (handle == NULL) { + SECU_PrintError (program_name, "problem getting certdb handle"); + goto nssdone; + } + + /* + * It would be fine to do the enable for all of these commands, + * but this way we check that everything but an overall verify + * can be done without it. That is, that the individual pieces + * work on their own. + */ + if (vcert) { + rv = CERT_EnableOCSPChecking (handle); + if (rv != SECSuccess) { + SECU_PrintError (program_name, "error enabling OCSP checking"); + goto nssdone; + } + } + + if ((ccert + vcert) && (responder_name != NULL)) { + rv = CERT_SetOCSPDefaultResponder (handle, responder_url, + responder_name); + if (rv != SECSuccess) { + SECU_PrintError (program_name, + "error setting default responder"); + goto nssdone; + } + + rv = CERT_EnableOCSPDefaultResponder (handle); + if (rv != SECSuccess) { + SECU_PrintError (program_name, + "error enabling default responder"); + goto nssdone; + } + } + } + +#define NOTYET(opt) \ + { \ + PR_fprintf (PR_STDERR, "%s not yet working\n", opt); \ + exit (-1); \ + } + + if (crequest) { + if (signer_name != NULL) { + NOTYET("-s"); + } + rv = create_request (out_file, handle, name, add_service_locator, + add_acceptable_responses); + } else if (dresponse) { + if (signer_name != NULL) { + NOTYET("-s"); + } + rv = dump_response (out_file, handle, name, responder_url); + } else if (prequest) { + rv = print_request (out_file, data); + } else if (presponse) { + rv = print_response (out_file, data, handle); + } else if (ccert) { + if (signer_name != NULL) { + NOTYET("-s"); + } + rv = get_cert_status (out_file, handle, name, verify_time); + } else if (vcert) { + if (signer_name != NULL) { + NOTYET("-s"); + } + rv = verify_cert (out_file, handle, name, cert_usage, verify_time); + } + + if (rv != SECSuccess) + SECU_PrintError (program_name, "error performing requested operation"); + else + retval = 0; + +nssdone: + if (data != NULL) { + SECITEM_FreeItem (data, PR_TRUE); + } + + if (handle != NULL) { + (void) CERT_DisableOCSPChecking (handle); + } + + if (NSS_Shutdown () != SECSuccess) { + exit(1); + } + +prdone: + PR_Cleanup (); + return retval; +} diff --git a/security/nss/cmd/oidcalc/Makefile b/security/nss/cmd/oidcalc/Makefile new file mode 100644 index 000000000..689240abd --- /dev/null +++ b/security/nss/cmd/oidcalc/Makefile @@ -0,0 +1,76 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/oidcalc/manifest.mn b/security/nss/cmd/oidcalc/manifest.mn new file mode 100644 index 000000000..7e1c3fad6 --- /dev/null +++ b/security/nss/cmd/oidcalc/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +# This next line is used by .mk files +# and gets translated into $LINCS in manifest.mnw +REQUIRES = seccmd dbm + +DEFINES = -DNSPR20 + +CSRCS = oidcalc.c + +PROGRAM = oidcalc diff --git a/security/nss/cmd/oidcalc/oidcalc.c b/security/nss/cmd/oidcalc/oidcalc.c new file mode 100644 index 000000000..cadc425a4 --- /dev/null +++ b/security/nss/cmd/oidcalc/oidcalc.c @@ -0,0 +1,117 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 <stdlib.h> +#include <string.h> + +int +main(int argc, char **argv) +{ + char *curstr; + char *nextstr; + unsigned int firstval; + unsigned int secondval; + unsigned int val; + unsigned char buf[5]; + int count; + + if ( argc != 2 ) { + fprintf(stderr, "wrong number of args\n"); + exit(-1); + } + + curstr = argv[1]; + + nextstr = strchr(curstr, '.'); + + if ( nextstr == NULL ) { + fprintf(stderr, "only one component\n"); + exit(-1); + } + + *nextstr = '\0'; + firstval = atoi(curstr); + + curstr = nextstr + 1; + + nextstr = strchr(curstr, '.'); + + if ( nextstr ) { + *nextstr = '\0'; + } + + secondval = atoi(curstr); + + if ( ( firstval < 0 ) || ( firstval > 2 ) ) { + fprintf(stderr, "first component out of range\n"); + exit(-1); + + } + + if ( ( secondval < 0 ) || ( secondval > 39 ) ) { + fprintf(stderr, "second component out of range\n"); + exit(-1); + } + + printf("0x%x, ", ( firstval * 40 ) + secondval ); + while ( nextstr ) { + curstr = nextstr + 1; + + nextstr = strchr(curstr, '.'); + + if ( nextstr ) { + *nextstr = '\0'; + } + + memset(buf, 0, sizeof(buf)); + val = atoi(curstr); + count = 0; + while ( val ) { + buf[count] = ( val & 0x7f ); + val = val >> 7; + count++; + } + + while ( count-- ) { + if ( count ) { + printf("0x%x, ", buf[count] | 0x80 ); + } else { + printf("0x%x, ", buf[count] ); + } + } + } + printf("\n"); + return 0; +} + diff --git a/security/nss/cmd/p7content/Makefile b/security/nss/cmd/p7content/Makefile new file mode 100644 index 000000000..4e39ffc3f --- /dev/null +++ b/security/nss/cmd/p7content/Makefile @@ -0,0 +1,75 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/p7content/manifest.mn b/security/nss/cmd/p7content/manifest.mn new file mode 100644 index 000000000..3ebd21743 --- /dev/null +++ b/security/nss/cmd/p7content/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +MODULE = nss + +CSRCS = p7content.c + +REQUIRES = seccmd + +PROGRAM = p7content + diff --git a/security/nss/cmd/p7content/p7content.c b/security/nss/cmd/p7content/p7content.c new file mode 100644 index 000000000..8b5ad65ce --- /dev/null +++ b/security/nss/cmd/p7content/p7content.c @@ -0,0 +1,271 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* + * p7content -- A command to display pkcs7 content. + * + * $Id$ + */ + +#include "nspr.h" +#include "secutil.h" +#include "plgetopt.h" +#include "secpkcs7.h" +#include "cert.h" +#include "certdb.h" +#include "nss.h" + +#if defined(XP_UNIX) +#include <unistd.h> +#endif + +#include <stdio.h> +#include <string.h> + +#if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4)) +extern int fwrite(char *, size_t, size_t, FILE*); +extern int fprintf(FILE *, char *, ...); +#endif + + + +static void +Usage(char *progName) +{ + fprintf(stderr, + "Usage: %s [-d dbdir] [-i input] [-o output]\n", + progName); + fprintf(stderr, + "%-20s Key/Cert database directory (default is ~/.netscape)\n", + "-d dbdir"); + fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n", + "-i input"); + fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n", + "-o output"); + exit(-1); +} + +static PRBool saw_content; + +static void +PrintBytes(void *arg, const char *buf, unsigned long len) +{ + FILE *out; + + out = arg; + fwrite (buf, len, 1, out); + + saw_content = PR_TRUE; +} + +/* + * XXX Someday we may want to do real policy stuff here. This allows + * anything to be decrypted, which is okay for a test program but does + * not set an example of how a real client with a real policy would + * need to do it. + */ +static PRBool +decryption_allowed(SECAlgorithmID *algid, PK11SymKey *key) +{ + return PR_TRUE; +} + +int +DecodeAndPrintFile(FILE *out, PRFileDesc *in, char *progName) +{ + SECItem derdata; + SEC_PKCS7ContentInfo *cinfo = NULL; + SEC_PKCS7DecoderContext *dcx; + + if (SECU_ReadDERFromFile(&derdata, in, PR_FALSE)) { + SECU_PrintError(progName, "error converting der"); + return -1; + } + + fprintf(out, + "Content printed between bars (newline added before second bar):"); + fprintf(out, "\n---------------------------------------------\n"); + + saw_content = PR_FALSE; + dcx = SEC_PKCS7DecoderStart(PrintBytes, out, NULL, NULL, + NULL, NULL, decryption_allowed); + if (dcx != NULL) { +#if 0 /* Test that decoder works when data is really streaming in. */ + { + unsigned long i; + for (i = 0; i < derdata.len; i++) + SEC_PKCS7DecoderUpdate(dcx, derdata.data + i, 1); + } +#else + SEC_PKCS7DecoderUpdate(dcx, (char *)derdata.data, derdata.len); +#endif + cinfo = SEC_PKCS7DecoderFinish(dcx); + } + + fprintf(out, "\n---------------------------------------------\n"); + + if (cinfo == NULL) + return -1; + + fprintf(out, "Content was%s encrypted.\n", + SEC_PKCS7ContentIsEncrypted(cinfo) ? "" : " not"); + + if (SEC_PKCS7ContentIsSigned(cinfo)) { + char *signer_cname, *signer_ename; + SECItem *signing_time; + + if (saw_content) { + fprintf(out, "Signature is "); + PORT_SetError(0); + if (SEC_PKCS7VerifySignature(cinfo, certUsageEmailSigner, PR_FALSE)) + fprintf(out, "valid.\n"); + else + fprintf(out, "invalid (Reason: %s).\n", + SECU_Strerror(PORT_GetError())); + } else { + fprintf(out, + "Content is detached; signature cannot be verified.\n"); + } + + signer_cname = SEC_PKCS7GetSignerCommonName(cinfo); + if (signer_cname != NULL) { + fprintf(out, "The signer's common name is %s\n", signer_cname); + PORT_Free(signer_cname); + } else { + fprintf(out, "No signer common name.\n"); + } + + signer_ename = SEC_PKCS7GetSignerEmailAddress(cinfo); + if (signer_ename != NULL) { + fprintf(out, "The signer's email address is %s\n", signer_ename); + PORT_Free(signer_ename); + } else { + fprintf(out, "No signer email address.\n"); + } + + signing_time = SEC_PKCS7GetSigningTime(cinfo); + if (signing_time != NULL) { + SECU_PrintUTCTime(out, signing_time, "Signing time", 0); + } else { + fprintf(out, "No signing time included.\n"); + } + } else { + fprintf(out, "Content was not signed.\n"); + } + + fprintf(out, "There were%s certs or crls included.\n", + SEC_PKCS7ContainsCertsOrCrls(cinfo) ? "" : " no"); + + SEC_PKCS7DestroyContentInfo(cinfo); + return 0; +} + + +/* + * Print the contents of a PKCS7 message, indicating signatures, etc. + */ + +int +main(int argc, char **argv) +{ + char *progName; + FILE *outFile; + PRFileDesc *inFile; + PLOptState *optstate; + PLOptStatus status; + SECStatus rv; + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + inFile = NULL; + outFile = NULL; + + /* + * Parse command line arguments + */ + optstate = PL_CreateOptState(argc, argv, "d:i:o:"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case 'd': + SECU_ConfigDirectory(optstate->value); + break; + + case 'i': + inFile = PR_Open(optstate->value, PR_RDONLY, 0); + if (!inFile) { + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", + progName, optstate->value); + return -1; + } + break; + + case 'o': + outFile = fopen(optstate->value, "w"); + if (!outFile) { + fprintf(stderr, "%s: unable to open \"%s\" for writing\n", + progName, optstate->value); + return -1; + } + break; + + default: + Usage(progName); + break; + } + } + if (status == PL_OPT_BAD) + Usage(progName); + + if (!inFile) inFile = PR_STDIN; + if (!outFile) outFile = stdout; + + /* Call the initialization routines */ + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + rv = NSS_Init(SECU_ConfigDirectory(NULL)); + if (rv != SECSuccess) { + SECU_PrintPRandOSError(progName); + return -1; + } + + if (DecodeAndPrintFile(outFile, inFile, progName)) { + SECU_PrintError(progName, "problem decoding data"); + return -1; + } + + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + + return 0; +} diff --git a/security/nss/cmd/p7env/Makefile b/security/nss/cmd/p7env/Makefile new file mode 100644 index 000000000..4e39ffc3f --- /dev/null +++ b/security/nss/cmd/p7env/Makefile @@ -0,0 +1,75 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/p7env/manifest.mn b/security/nss/cmd/p7env/manifest.mn new file mode 100644 index 000000000..7d51282f9 --- /dev/null +++ b/security/nss/cmd/p7env/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +MODULE = nss + +CSRCS = p7env.c + +REQUIRES = seccmd + +PROGRAM = p7env + diff --git a/security/nss/cmd/p7env/p7env.c b/security/nss/cmd/p7env/p7env.c new file mode 100644 index 000000000..54d79fbfc --- /dev/null +++ b/security/nss/cmd/p7env/p7env.c @@ -0,0 +1,273 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* + * p7env -- A command to create a pkcs7 enveloped data. + * + * $Id$ + */ + +#include "nspr.h" +#include "secutil.h" +#include "plgetopt.h" +#include "secpkcs7.h" +#include "cert.h" +#include "certdb.h" +#include "nss.h" + +#if defined(XP_UNIX) +#include <unistd.h> +#endif + +#include <stdio.h> +#include <string.h> + +#if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4)) +extern int fread(char *, size_t, size_t, FILE*); +extern int fwrite(char *, size_t, size_t, FILE*); +extern int fprintf(FILE *, char *, ...); +#endif + +extern void SEC_Init(void); /* XXX */ + + +static void +Usage(char *progName) +{ + fprintf(stderr, + "Usage: %s -r recipient [-d dbdir] [-i input] [-o output]\n", + progName); + fprintf(stderr, "%-20s Nickname of cert to use for encryption\n", + "-r recipient"); + fprintf(stderr, "%-20s Cert database directory (default is ~/.netscape)\n", + "-d dbdir"); + fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n", + "-i input"); + fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n", + "-o output"); + exit(-1); +} + +struct recipient { + struct recipient *next; + char *nickname; + CERTCertificate *cert; +}; + +static void +EncryptOut(void *arg, const char *buf, unsigned long len) +{ + FILE *out; + + out = arg; + fwrite (buf, len, 1, out); +} + +static int +EncryptFile(FILE *outFile, FILE *inFile, struct recipient *recipients, + char *progName) +{ + SEC_PKCS7ContentInfo *cinfo; + SEC_PKCS7EncoderContext *ecx; + struct recipient *rcpt; + SECStatus rv; + + if (outFile == NULL || inFile == NULL || recipients == NULL) + return -1; + + /* XXX Need a better way to handle that certUsage stuff! */ + /* XXX keysize? */ + cinfo = SEC_PKCS7CreateEnvelopedData (recipients->cert, + certUsageEmailRecipient, + NULL, SEC_OID_DES_EDE3_CBC, 0, + NULL, NULL); + if (cinfo == NULL) + return -1; + + for (rcpt = recipients->next; rcpt != NULL; rcpt = rcpt->next) { + rv = SEC_PKCS7AddRecipient (cinfo, rcpt->cert, certUsageEmailRecipient, + NULL); + if (rv != SECSuccess) { + SECU_PrintError(progName, "error adding recipient \"%s\"", + rcpt->nickname); + return -1; + } + } + + ecx = SEC_PKCS7EncoderStart (cinfo, EncryptOut, outFile, NULL); + if (ecx == NULL) + return -1; + + for (;;) { + char ibuf[1024]; + int nb; + + if (feof(inFile)) + break; + nb = fread(ibuf, 1, sizeof(ibuf), inFile); + if (nb == 0) { + if (ferror(inFile)) { + PORT_SetError(SEC_ERROR_IO); + rv = SECFailure; + } + break; + } + rv = SEC_PKCS7EncoderUpdate(ecx, ibuf, nb); + if (rv != SECSuccess) + break; + } + + if (SEC_PKCS7EncoderFinish(ecx, NULL, NULL) != SECSuccess) + rv = SECFailure; + + SEC_PKCS7DestroyContentInfo (cinfo); + + if (rv != SECSuccess) + return -1; + + return 0; +} + +int +main(int argc, char **argv) +{ + char *progName; + FILE *inFile, *outFile; + char *certName; + CERTCertDBHandle *certHandle; + CERTCertificate *cert; + struct recipient *recipients, *rcpt; + PLOptState *optstate; + PLOptStatus status; + SECStatus rv; + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + inFile = NULL; + outFile = NULL; + certName = NULL; + recipients = NULL; + rcpt = NULL; + + /* + * Parse command line arguments + * XXX This needs to be enhanced to allow selection of algorithms + * and key sizes (or to look up algorithms and key sizes for each + * recipient in the magic database). + */ + optstate = PL_CreateOptState(argc, argv, "d:i:o:r:"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case '?': + Usage(progName); + break; + + case 'd': + SECU_ConfigDirectory(optstate->value); + break; + + case 'i': + inFile = fopen(optstate->value, "r"); + if (!inFile) { + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", + progName, optstate->value); + return -1; + } + break; + + case 'o': + outFile = fopen(optstate->value, "w"); + if (!outFile) { + fprintf(stderr, "%s: unable to open \"%s\" for writing\n", + progName, optstate->value); + return -1; + } + break; + + case 'r': + if (rcpt == NULL) { + recipients = rcpt = PORT_Alloc (sizeof(struct recipient)); + } else { + rcpt->next = PORT_Alloc (sizeof(struct recipient)); + rcpt = rcpt->next; + } + if (rcpt == NULL) { + fprintf(stderr, "%s: unable to allocate recipient struct\n", + progName); + return -1; + } + rcpt->nickname = strdup(optstate->value); + rcpt->cert = NULL; + rcpt->next = NULL; + break; + } + } + + if (!recipients) Usage(progName); + + if (!inFile) inFile = stdin; + if (!outFile) outFile = stdout; + + /* Call the libsec initialization routines */ + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + rv = NSS_Init(SECU_ConfigDirectory(NULL)); + if (rv != SECSuccess) { + SECU_PrintPRandOSError(progName); + return -1; + } + + /* open cert database */ + certHandle = CERT_GetDefaultCertDB(); + if (certHandle == NULL) { + return -1; + } + + /* find certs */ + for (rcpt = recipients; rcpt != NULL; rcpt = rcpt->next) { + rcpt->cert = CERT_FindCertByNickname(certHandle, rcpt->nickname); + if (rcpt->cert == NULL) { + SECU_PrintError(progName, + "the cert for name \"%s\" not found in database", + rcpt->nickname); + return -1; + } + } + + if (EncryptFile(outFile, inFile, recipients, progName)) { + SECU_PrintError(progName, "problem encrypting data"); + return -1; + } + + return 0; +} diff --git a/security/nss/cmd/p7sign/Makefile b/security/nss/cmd/p7sign/Makefile new file mode 100644 index 000000000..4e39ffc3f --- /dev/null +++ b/security/nss/cmd/p7sign/Makefile @@ -0,0 +1,75 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/p7sign/manifest.mn b/security/nss/cmd/p7sign/manifest.mn new file mode 100644 index 000000000..d5134df48 --- /dev/null +++ b/security/nss/cmd/p7sign/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +MODULE = nss + +CSRCS = p7sign.c + +REQUIRES = seccmd + +PROGRAM = p7sign + diff --git a/security/nss/cmd/p7sign/p7sign.c b/security/nss/cmd/p7sign/p7sign.c new file mode 100644 index 000000000..09cbd8dcd --- /dev/null +++ b/security/nss/cmd/p7sign/p7sign.c @@ -0,0 +1,292 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* + * p7sign -- A command to create a *detached* pkcs7 signature (over a given + * input file). + * + * $Id$ + */ + +#include "nspr.h" +#include "plgetopt.h" +#include "secutil.h" +#include "secpkcs7.h" +#include "cert.h" +#include "certdb.h" +#include "sechash.h" /* for HASH_GetHashObject() */ +#include "nss.h" +#include "pk11func.h" + +#if defined(XP_UNIX) +#include <unistd.h> +#endif + +#include <stdio.h> +#include <string.h> + +#if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4)) +extern int fread(char *, size_t, size_t, FILE*); +extern int fwrite(char *, size_t, size_t, FILE*); +extern int fprintf(FILE *, char *, ...); +#endif + +char* KeyDbPassword = 0; + + +char* MyPK11PasswordFunc (PK11SlotInfo *slot, PRBool retry, void* arg) +{ + char *ret=0; + + if (retry == PR_TRUE) + return NULL; + ret = PL_strdup (KeyDbPassword); + return ret; +} + + +static void +Usage(char *progName) +{ + fprintf(stderr, + "Usage: %s -k keyname [-d keydir] [-i input] [-o output]\n", + progName); + fprintf(stderr, "%-20s Nickname of key to use for signature\n", + "-k keyname"); + fprintf(stderr, "%-20s Key database directory (default is ~/.netscape)\n", + "-d keydir"); + fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n", + "-i input"); + fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n", + "-o output"); + fprintf(stderr, "%-20s Encapsulate content in signature message\n", + "-e"); + fprintf(stderr, "%-20s Password to the key databse\n", "-p"); + exit(-1); +} + +static void +SignOut(void *arg, const char *buf, unsigned long len) +{ + FILE *out; + + out = (FILE*) arg; + fwrite (buf, len, 1, out); +} + +static int +CreateDigest(SECItem *data, char *digestdata, unsigned int *len, unsigned int maxlen) +{ + const SECHashObject *hashObj; + void *hashcx; + + /* XXX probably want to extend interface to allow other hash algorithms */ + hashObj = HASH_GetHashObject(HASH_AlgSHA1); + + hashcx = (* hashObj->create)(); + if (hashcx == NULL) + return -1; + + (* hashObj->begin)(hashcx); + (* hashObj->update)(hashcx, data->data, data->len); + (* hashObj->end)(hashcx, (unsigned char *)digestdata, len, maxlen); + (* hashObj->destroy)(hashcx, PR_TRUE); + return 0; +} + +static int +SignFile(FILE *outFile, PRFileDesc *inFile, CERTCertificate *cert, + PRBool encapsulated) +{ + int nb; + char digestdata[32]; + unsigned int len; + SECItem digest, data2sign; + SEC_PKCS7ContentInfo *cinfo; + SECStatus rv; + + if (outFile == NULL || inFile == NULL || cert == NULL) + return -1; + + /* suck the file in */ + if (SECU_ReadDERFromFile(&data2sign, inFile, PR_FALSE) != SECSuccess) + return -1; + + if (!encapsulated) { + /* unfortunately, we must create the digest ourselves */ + /* SEC_PKCS7CreateSignedData should have a flag to not include */ + /* the content for non-encapsulated content at encode time, but */ + /* should always compute the hash itself */ + if (CreateDigest(&data2sign, digestdata, &len, 32) < 0) + return -1; + digest.data = (unsigned char *)digestdata; + digest.len = len; + } + + /* XXX Need a better way to handle that usage stuff! */ + cinfo = SEC_PKCS7CreateSignedData (cert, certUsageEmailSigner, NULL, + SEC_OID_SHA1, + encapsulated ? NULL : &digest, + NULL, NULL); + if (cinfo == NULL) + return -1; + + if (encapsulated) { + SEC_PKCS7SetContent(cinfo, (char *)data2sign.data, data2sign.len); + } + + rv = SEC_PKCS7IncludeCertChain (cinfo, NULL); + if (rv != SECSuccess) { + SEC_PKCS7DestroyContentInfo (cinfo); + return -1; + } + + rv = SEC_PKCS7Encode (cinfo, SignOut, outFile, NULL, + NULL, NULL); + + SEC_PKCS7DestroyContentInfo (cinfo); + + if (rv != SECSuccess) + return -1; + + return 0; +} + +int +main(int argc, char **argv) +{ + char *progName; + FILE *outFile; + PRFileDesc *inFile; + char *keyName; + CERTCertDBHandle *certHandle; + CERTCertificate *cert; + PRBool encapsulated = PR_FALSE; + PLOptState *optstate; + PLOptStatus status; + SECStatus rv; + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + inFile = NULL; + outFile = NULL; + keyName = NULL; + + /* + * Parse command line arguments + */ + optstate = PL_CreateOptState(argc, argv, "ed:k:i:o:p:"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case '?': + Usage(progName); + break; + + case 'e': + /* create a message with the signed content encapsulated */ + encapsulated = PR_TRUE; + break; + + case 'd': + SECU_ConfigDirectory(optstate->value); + break; + + case 'i': + inFile = PR_Open(optstate->value, PR_RDONLY, 0); + if (!inFile) { + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", + progName, optstate->value); + return -1; + } + break; + + case 'k': + keyName = strdup(optstate->value); + break; + + case 'o': + outFile = fopen(optstate->value, "w"); + if (!outFile) { + fprintf(stderr, "%s: unable to open \"%s\" for writing\n", + progName, optstate->value); + return -1; + } + break; + case 'p': + KeyDbPassword = strdup (optstate->value); + break; + } + } + + if (!keyName) Usage(progName); + + if (!inFile) inFile = PR_STDIN; + if (!outFile) outFile = stdout; + + /* Call the initialization routines */ + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + rv = NSS_Init(SECU_ConfigDirectory(NULL)); + if (rv != SECSuccess) { + SECU_PrintPRandOSError(progName); + return -1; + } + + PK11_SetPasswordFunc (MyPK11PasswordFunc); + + /* open cert database */ + certHandle = CERT_GetDefaultCertDB(); + if (certHandle == NULL) { + return -1; + } + + /* find cert */ + cert = CERT_FindCertByNickname(certHandle, keyName); + if (cert == NULL) { + SECU_PrintError(progName, + "the corresponding cert for key \"%s\" does not exist", + keyName); + return -1; + } + + if (SignFile(outFile, inFile, cert, encapsulated)) { + SECU_PrintError(progName, "problem signing data"); + return -1; + } + + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + + return 0; +} diff --git a/security/nss/cmd/p7verify/Makefile b/security/nss/cmd/p7verify/Makefile new file mode 100644 index 000000000..4e39ffc3f --- /dev/null +++ b/security/nss/cmd/p7verify/Makefile @@ -0,0 +1,75 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/p7verify/manifest.mn b/security/nss/cmd/p7verify/manifest.mn new file mode 100644 index 000000000..7e841c700 --- /dev/null +++ b/security/nss/cmd/p7verify/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +MODULE = nss + +CSRCS = p7verify.c + +REQUIRES = seccmd + +PROGRAM = p7verify + diff --git a/security/nss/cmd/p7verify/p7verify.c b/security/nss/cmd/p7verify/p7verify.c new file mode 100644 index 000000000..81815081b --- /dev/null +++ b/security/nss/cmd/p7verify/p7verify.c @@ -0,0 +1,305 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* + * p7verify -- A command to do a verification of a *detached* pkcs7 signature. + * + * $Id$ + */ + +#include "nspr.h" +#include "secutil.h" +#include "plgetopt.h" +#include "secpkcs7.h" +#include "cert.h" +#include "certdb.h" +#include "secoid.h" +#include "sechash.h" /* for HASH_GetHashObject() */ +#include "nss.h" + +#if defined(XP_UNIX) +#include <unistd.h> +#endif + +#include <stdio.h> +#include <string.h> + +#if (defined(XP_WIN) && !defined(WIN32)) || (defined(__sun) && !defined(SVR4)) +extern int fread(char *, size_t, size_t, FILE*); +extern int fprintf(FILE *, char *, ...); +#endif + + +static HASH_HashType +AlgorithmToHashType(SECAlgorithmID *digestAlgorithms) +{ + + SECOidTag tag; + + tag = SECOID_GetAlgorithmTag(digestAlgorithms); + + switch (tag) { + case SEC_OID_MD2: + return HASH_AlgMD2; + case SEC_OID_MD5: + return HASH_AlgMD5; + case SEC_OID_SHA1: + return HASH_AlgSHA1; + default: + fprintf(stderr, "should never get here\n"); + return HASH_AlgNULL; + } +} + +static int +DigestFile(unsigned char *digest, unsigned int *len, unsigned int maxLen, + FILE *inFile, HASH_HashType hashType) +{ + int nb; + unsigned char ibuf[4096]; + const SECHashObject *hashObj; + void *hashcx; + + hashObj = HASH_GetHashObject(hashType); + + hashcx = (* hashObj->create)(); + if (hashcx == NULL) + return -1; + + (* hashObj->begin)(hashcx); + + for (;;) { + if (feof(inFile)) break; + nb = fread(ibuf, 1, sizeof(ibuf), inFile); + if (nb != sizeof(ibuf)) { + if (nb == 0) { + if (ferror(inFile)) { + PORT_SetError(SEC_ERROR_IO); + (* hashObj->destroy)(hashcx, PR_TRUE); + return -1; + } + /* eof */ + break; + } + } + (* hashObj->update)(hashcx, ibuf, nb); + } + + (* hashObj->end)(hashcx, digest, len, maxLen); + (* hashObj->destroy)(hashcx, PR_TRUE); + + return 0; +} + + +static void +Usage(char *progName) +{ + fprintf(stderr, + "Usage: %s -c content -s signature [-d dbdir] [-u certusage]\n", + progName); + fprintf(stderr, "%-20s content file that was signed\n", + "-c content"); + fprintf(stderr, "%-20s file containing signature for that content\n", + "-s signature"); + fprintf(stderr, + "%-20s Key/Cert database directory (default is ~/.netscape)\n", + "-d dbdir"); + fprintf(stderr, "%-20s Define the type of certificate usage (default is certUsageEmailSigner)\n", + "-u certusage"); + fprintf(stderr, "%-25s 0 - certUsageSSLClient\n", " "); + fprintf(stderr, "%-25s 1 - certUsageSSLServer\n", " "); + fprintf(stderr, "%-25s 2 - certUsageSSLServerWithStepUp\n", " "); + fprintf(stderr, "%-25s 3 - certUsageSSLCA\n", " "); + fprintf(stderr, "%-25s 4 - certUsageEmailSigner\n", " "); + fprintf(stderr, "%-25s 5 - certUsageEmailRecipient\n", " "); + fprintf(stderr, "%-25s 6 - certUsageObjectSigner\n", " "); + fprintf(stderr, "%-25s 7 - certUsageUserCertImport\n", " "); + fprintf(stderr, "%-25s 8 - certUsageVerifyCA\n", " "); + fprintf(stderr, "%-25s 9 - certUsageProtectedObjectSigner\n", " "); + fprintf(stderr, "%-25s 10 - certUsageStatusResponder\n", " "); + fprintf(stderr, "%-25s 11 - certUsageAnyCA\n", " "); + + exit(-1); +} + +static int +HashDecodeAndVerify(FILE *out, FILE *content, PRFileDesc *signature, + SECCertUsage usage, char *progName) +{ + SECItem derdata; + SEC_PKCS7ContentInfo *cinfo; + SEC_PKCS7SignedData *signedData; + HASH_HashType digestType; + SECItem digest; + unsigned char buffer[32]; + + if (SECU_ReadDERFromFile(&derdata, signature, PR_FALSE) != SECSuccess) { + SECU_PrintError(progName, "error reading signature file"); + return -1; + } + + cinfo = SEC_PKCS7DecodeItem(&derdata, NULL, NULL, NULL, NULL, + NULL, NULL, NULL); + if (cinfo == NULL) + return -1; + + if (! SEC_PKCS7ContentIsSigned(cinfo)) { + fprintf (out, "Signature file is pkcs7 data, but not signed.\n"); + return -1; + } + + signedData = cinfo->content.signedData; + + /* assume that there is only one digest algorithm for now */ + digestType = AlgorithmToHashType(signedData->digestAlgorithms[0]); + if (digestType == HASH_AlgNULL) { + fprintf (out, "Invalid hash algorithmID\n"); + return -1; + } + + digest.data = buffer; + if (DigestFile (digest.data, &digest.len, 32, content, digestType)) { + SECU_PrintError (progName, "problem computing message digest"); + return -1; + } + + fprintf(out, "Signature is "); + if (SEC_PKCS7VerifyDetachedSignature (cinfo, usage, &digest, digestType, + PR_FALSE)) + fprintf(out, "valid.\n"); + else + fprintf(out, "invalid (Reason: %s).\n", + SECU_Strerror(PORT_GetError())); + + SEC_PKCS7DestroyContentInfo(cinfo); + return 0; +} + + +int +main(int argc, char **argv) +{ + char *progName; + FILE *contentFile, *outFile; + PRFileDesc *signatureFile; + SECCertUsage certUsage = certUsageEmailSigner; + PLOptState *optstate; + PLOptStatus status; + SECStatus rv; + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + contentFile = NULL; + signatureFile = NULL; + outFile = NULL; + + /* + * Parse command line arguments + */ + optstate = PL_CreateOptState(argc, argv, "c:d:o:s:u:"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case '?': + Usage(progName); + break; + + case 'c': + contentFile = fopen(optstate->value, "r"); + if (!contentFile) { + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", + progName, optstate->value); + return -1; + } + break; + + case 'd': + SECU_ConfigDirectory(optstate->value); + break; + + case 'o': + outFile = fopen(optstate->value, "w"); + if (!outFile) { + fprintf(stderr, "%s: unable to open \"%s\" for writing\n", + progName, optstate->value); + return -1; + } + break; + + case 's': + signatureFile = PR_Open(optstate->value, PR_RDONLY, 0); + if (!signatureFile) { + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", + progName, optstate->value); + return -1; + } + break; + + case 'u': { + int usageType; + + usageType = atoi (strdup(optstate->value)); + if (usageType < certUsageSSLClient || usageType > certUsageAnyCA) + return -1; + certUsage = (SECCertUsage)usageType; + break; + } + + } + } + + if (!contentFile) Usage (progName); + if (!signatureFile) Usage (progName); + if (!outFile) outFile = stdout; + + /* Call the libsec initialization routines */ + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + rv = NSS_Init(SECU_ConfigDirectory(NULL)); + if (rv != SECSuccess) { + SECU_PrintPRandOSError(progName); + return -1; + } + + if (HashDecodeAndVerify(outFile, contentFile, signatureFile, + certUsage, progName)) { + SECU_PrintError(progName, "problem decoding/verifying signature"); + return -1; + } + + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + + return 0; +} diff --git a/security/nss/cmd/pk12util/Makefile b/security/nss/cmd/pk12util/Makefile new file mode 100644 index 000000000..8650a607d --- /dev/null +++ b/security/nss/cmd/pk12util/Makefile @@ -0,0 +1,76 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/pk12util/manifest.mn b/security/nss/cmd/pk12util/manifest.mn new file mode 100644 index 000000000..40fd6d6ac --- /dev/null +++ b/security/nss/cmd/pk12util/manifest.mn @@ -0,0 +1,51 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +DEFINES += -DNSPR20 + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +CSRCS = \ + pk12util.c \ + $(NULL) + +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = dbm seccmd + +PROGRAM = pk12util + +# USE_STATIC_LIBS = 1 diff --git a/security/nss/cmd/pk12util/pk12util.c b/security/nss/cmd/pk12util/pk12util.c new file mode 100644 index 000000000..255c189d9 --- /dev/null +++ b/security/nss/cmd/pk12util/pk12util.c @@ -0,0 +1,867 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "secutil.h" +#include "pk11func.h" +#include "pkcs12.h" +#include "p12plcy.h" +#include "pk12util.h" +#include "nss.h" +#include "secport.h" +#include "certdb.h" + +#define PKCS12_IN_BUFFER_SIZE 200 + +static char *progName; +PRBool pk12_debugging = PR_FALSE; + +PRIntn pk12uErrno = 0; + +static void +Usage(char *progName) +{ +#define FPS PR_fprintf(PR_STDERR, + FPS "Usage: %s -i importfile [-d certdir] [-P dbprefix] [-h tokenname]\n", + progName); + FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n"); + FPS "\t\t [-v]\n"); + FPS "Usage: %s -o exportfile -n certname [-d certdir] [-P dbprefix]\n", progName); + FPS "\t\t [-k slotpwfile | -K slotpw] [-w p12filepwfile | -W p12filepw]\n"); + FPS "\t\t [-v]\n"); + exit(PK12UERR_USAGE); +} + +static PRBool +p12u_OpenExportFile(p12uContext *p12cxt, PRBool fileRead) +{ + if(!p12cxt || !p12cxt->filename) { + return PR_FALSE; + } + + if(fileRead) { + p12cxt->file = PR_Open(p12cxt->filename, + PR_RDONLY, 0400); + } else { + p12cxt->file = PR_Open(p12cxt->filename, + PR_CREATE_FILE | PR_RDWR | PR_TRUNCATE, + 0600); + } + + if(!p12cxt->file) { + p12cxt->error = PR_TRUE; + PR_SetError(SEC_ERROR_NO_MEMORY, 0); + return PR_FALSE; + } + + return PR_TRUE; +} + +static void +p12u_DestroyExportFileInfo(p12uContext **exp_ptr, PRBool removeFile) +{ + if(!exp_ptr || !(*exp_ptr)) { + return; + } + + if((*exp_ptr)->file != NULL) { + PR_Close((*exp_ptr)->file); + } + + if((*exp_ptr)->filename != NULL) { + if(removeFile) { + PR_Delete((*exp_ptr)->filename); + } + PR_Free((*exp_ptr)->filename); + } + + PR_Free(*exp_ptr); + *exp_ptr = NULL; +} + +static p12uContext * +p12u_InitFile(PRBool fileImport, char *filename) +{ + p12uContext *p12cxt; + PRBool fileExist; + + if(fileImport) + fileExist = PR_TRUE; + else + fileExist = PR_FALSE; + + p12cxt = (p12uContext *)PORT_ZAlloc(sizeof(p12uContext)); + if(!p12cxt) { + PR_SetError(SEC_ERROR_NO_MEMORY, 0); + return NULL; + } + + p12cxt->error = PR_FALSE; + p12cxt->errorValue = 0; + p12cxt->filename = strdup(filename); + + if(!p12u_OpenExportFile(p12cxt, fileImport)) { + PR_SetError(p12cxt->errorValue, 0); + p12u_DestroyExportFileInfo(&p12cxt, PR_FALSE); + return NULL; + } + + return p12cxt; +} + +SECItem * +P12U_NicknameCollisionCallback(SECItem *old_nick, PRBool *cancel, void *wincx) +{ + char *nick = NULL; + SECItem *ret_nick = NULL; + + if(cancel == NULL) { + pk12uErrno = PK12UERR_USER_CANCELLED; + return NULL; + } + + if (!old_nick) + fprintf(stdout, "pk12util: no nickname for cert...not handled\n"); + + /* XXX not handled yet */ + *cancel = PR_TRUE; + return NULL; + +#if 0 + nick = strdup( DEFAULT_CERT_NICKNAME ); + + if(old_nick && !PORT_Strcmp((char *)old_nick->data, nick)) { + PORT_Free(nick); + return NULL; + } + + ret_nick = (SECItem *)PORT_ZAlloc(sizeof(SECItem)); + if(ret_nick == NULL) { + PORT_Free(nick); + return NULL; + } + + ret_nick->data = (unsigned char *)nick; + ret_nick->len = PORT_Strlen(nick); + + return ret_nick; +#endif +} + +static SECStatus +p12u_SwapUnicodeBytes(SECItem *uniItem) +{ + unsigned int i; + unsigned char a; + if((uniItem == NULL) || (uniItem->len % 2)) { + return SECFailure; + } + for(i = 0; i < uniItem->len; i += 2) { + a = uniItem->data[i]; + uniItem->data[i] = uniItem->data[i+1]; + uniItem->data[i+1] = a; + } + return SECSuccess; +} + +static PRBool +p12u_ucs2_ascii_conversion_function(PRBool toUnicode, + unsigned char *inBuf, + unsigned int inBufLen, + unsigned char *outBuf, + unsigned int maxOutBufLen, + unsigned int *outBufLen, + PRBool swapBytes) +{ + SECItem it = { 0 }; + SECItem *dup = NULL; + PRBool ret; + /* If converting Unicode to ASCII, swap bytes before conversion + * as neccessary. + */ + if (pk12_debugging) { + int i; + printf("Converted from:\n"); + for (i=0; i<inBufLen; i++) { + printf("%2x ", inBuf[i]); + /*if (i%60 == 0) printf("\n");*/ + } + printf("\n"); + } + it.data = inBuf; + it.len = inBufLen; + dup = SECITEM_DupItem(&it); + if (!toUnicode && swapBytes) { + if (p12u_SwapUnicodeBytes(dup) != SECSuccess) { + SECITEM_ZfreeItem(dup, PR_TRUE); + return PR_FALSE; + } + } + /* Perform the conversion. */ + ret = PORT_UCS2_UTF8Conversion(toUnicode, dup->data, dup->len, + outBuf, maxOutBufLen, outBufLen); + if (dup) + SECITEM_ZfreeItem(dup, PR_TRUE); + /* If converting ASCII to Unicode, swap bytes before returning + * as neccessary. + */ +#if 0 + if (toUnicode && swapBytes) { + it.data = outBuf; + it.len = *outBufLen; + dup = SECITEM_DupItem(&it); + if (p12u_SwapUnicodeBytes(dup) != SECSuccess) { + SECITEM_ZfreeItem(dup, PR_TRUE); + return PR_FALSE; + } + memcpy(outBuf, dup->data, *outBufLen); + SECITEM_ZfreeItem(dup, PR_TRUE); + } +#endif + if (pk12_debugging) { + int i; + printf("Converted to:\n"); + for (i=0; i<*outBufLen; i++) { + printf("%2x ", outBuf[i]); + /*if (i%60 == 0) printf("\n");*/ + } + printf("\n"); + } + return ret; +} + +SECStatus +P12U_UnicodeConversion(PRArenaPool *arena, SECItem *dest, SECItem *src, + PRBool toUnicode, PRBool swapBytes) +{ + unsigned int allocLen; + if(!dest || !src) { + return SECFailure; + } + allocLen = ((toUnicode) ? (src->len << 2) : src->len); + if(arena) { + dest->data = PORT_ArenaZAlloc(arena, allocLen); + } else { + dest->data = PORT_ZAlloc(allocLen); + } + if(PORT_UCS2_ASCIIConversion(toUnicode, src->data, src->len, + dest->data, allocLen, &dest->len, + swapBytes) == PR_FALSE) { + if(!arena) { + PORT_Free(dest->data); + } + dest->data = NULL; + return SECFailure; + } + return SECSuccess; +} + +/* + * + */ +SECItem * +P12U_GetP12FilePassword(PRBool confirmPw, secuPWData *p12FilePw) +{ + char *p0 = NULL, *p1 = NULL; + SECItem *pwItem = NULL; + + if (p12FilePw == NULL || p12FilePw->source == PW_NONE) { + for (;;) { + p0 = SECU_GetPasswordString(NULL, + "Enter password for PKCS12 file: "); + if (!confirmPw) + break; + p1 = SECU_GetPasswordString(NULL, "Re-enter password: "); + if (PL_strcmp(p0, p1) == 0) + break; + } + } else if (p12FilePw->source == PW_FROMFILE) { + p0 = SECU_FilePasswd(NULL, PR_FALSE, p12FilePw->data); + } else { /* Plaintext */ + p0 = p12FilePw->data; + } + + pwItem = SECITEM_AllocItem(NULL, NULL, PL_strlen(p0) + 1); + memcpy(pwItem->data, p0, pwItem->len); + + PORT_Memset(p0, 0, PL_strlen(p0)); + PORT_Free(p0); + + PORT_Memset(p1, 0, PL_strlen(p1)); + PORT_Free(p1); + + return pwItem; +} + +SECStatus +P12U_InitSlot(PK11SlotInfo *slot, secuPWData *slotPw) +{ + SECStatus rv; + + /* New databases, initialize keydb password. */ + if (PK11_NeedUserInit(slot)) { + rv = SECU_ChangePW(slot, + (slotPw->source == PW_PLAINTEXT) ? slotPw->data : 0, + (slotPw->source == PW_FROMFILE) ? slotPw->data : 0); + if (rv != SECSuccess) { + SECU_PrintError(progName, "Failed to initialize slot \"%s\"", + PK11_GetSlotName(slot)); + return SECFailure; + } + } + + if (PK11_Authenticate(slot, PR_TRUE, slotPw) != SECSuccess) { + SECU_PrintError(progName, + "Failed to authenticate to PKCS11 slot"); + PORT_SetError(SEC_ERROR_USER_CANCELLED); + pk12uErrno = PK12UERR_USER_CANCELLED; + return SECFailure; + } + + return SECSuccess; +} + +/* + * given a filename for pkcs12 file, imports certs and keys + * + * Change: altitude + * I've changed this function so that it takes the keydb and pkcs12 file + * passwords from files. The "pwdKeyDB" and "pwdP12File" + * variables have been added for this purpose. + */ +PRIntn +P12U_ImportPKCS12Object(char *in_file, PK11SlotInfo *slot, + secuPWData *slotPw, secuPWData *p12FilePw) +{ + p12uContext *p12cxt = NULL; + unsigned char inBuf[PKCS12_IN_BUFFER_SIZE]; + SEC_PKCS12DecoderContext *p12dcx = NULL; + SECItem *pwitem = NULL, uniPwitem = { 0 }; + SECItem p12file = { 0 }; + SECStatus rv = SECFailure; + PRBool swapUnicode = PR_FALSE; + int error; + +#ifdef IS_LITTLE_ENDIAN + swapUnicode = PR_TRUE; +#endif + + rv = P12U_InitSlot(slot, slotPw); + if (rv != SECSuccess) { + SECU_PrintError(progName, "Failed to authenticate to \"%s\"", + PK11_GetSlotName(slot)); + pk12uErrno = PK12UERR_PK11GETSLOT; + goto loser; + } + + p12cxt = p12u_InitFile(PR_TRUE, in_file); + if(!p12cxt) { + SECU_PrintError(progName,"Initialization failed: %s", in_file); + pk12uErrno = PK12UERR_INIT_FILE; + goto loser; + } + + /* get the password */ + pwitem = P12U_GetP12FilePassword(PR_FALSE, p12FilePw); + if (!pwitem) { + pk12uErrno = PK12UERR_USER_CANCELLED; + goto loser; + } + + if(P12U_UnicodeConversion(NULL, &uniPwitem, pwitem, PR_TRUE, + swapUnicode) != SECSuccess) { + SECU_PrintError(progName,"Unicode conversion failed"); + pk12uErrno = PK12UERR_UNICODECONV; + goto loser; + } + + /* init the decoder context */ + p12dcx = SEC_PKCS12DecoderStart(&uniPwitem, slot, slotPw, + NULL, NULL, NULL, NULL, NULL); + if(!p12dcx) { + SECU_PrintError(progName,"PKCS12 decoder start failed"); + pk12uErrno = PK12UERR_PK12DECODESTART; + goto loser; + } + + /* decode the item */ + rv = SECU_FileToItem(&p12file, p12cxt->file); + if (rv != SECSuccess) { + SECU_PrintError(progName,"Failed to read from import file"); + goto loser; + } + rv = SEC_PKCS12DecoderUpdate(p12dcx, p12file.data, p12file.len); + + if(rv != SECSuccess) { + error = PR_GetError(); + if(error == SEC_ERROR_DECRYPTION_DISALLOWED) { + PR_SetError(error, 0); + goto loser; + } +#ifdef EXTRA + /* unable to import as a new blob, it might be an old one */ + if(p12u_TryToImportOldPDU(p12cxt, pwitem, slot, import_arg->nickCb, + import_arg->proto_win) != SECSuccess) { + goto loser; + } + goto tried_pdu_import; +#endif /* EXTRA */ + SECU_PrintError(progName,"PKCS12 decoding failed"); + pk12uErrno = PK12UERR_DECODE; + } + + rv = SECFailure; + + /* does the blob authenticate properly? */ + if(SEC_PKCS12DecoderVerify(p12dcx) != SECSuccess) { + SECU_PrintError(progName,"PKCS12 decode not verified"); + pk12uErrno = PK12UERR_DECODEVERIFY; + goto loser; + } + + /* make sure the bags are okey dokey -- nicknames correct, etc. */ + if (SEC_PKCS12DecoderValidateBags(p12dcx, P12U_NicknameCollisionCallback) + != SECSuccess) { + if (PORT_GetError() == SEC_ERROR_PKCS12_DUPLICATE_DATA) { + pk12uErrno = PK12UERR_CERTALREADYEXISTS; + } else { + pk12uErrno = PK12UERR_DECODEVALIBAGS; + } + SECU_PrintError(progName,"PKCS12 decode validate bags failed"); + goto loser; + } + + /* stuff 'em in */ + if(SEC_PKCS12DecoderImportBags(p12dcx) != SECSuccess) { + SECU_PrintError(progName,"PKCS12 decode import bags failed"); + pk12uErrno = PK12UERR_DECODEIMPTBAGS; + goto loser; + } + +#if 0 + /* important - to add the password hash into the key database */ + rv = PK11_CheckUserPassword(slot, pw_string); + if( rv != SECSuccess ) { + SECU_PrintError(progName,"Failed to CheckUserPassword"); + exit(-1); + } +#endif + + PR_Close(p12cxt->file); + p12cxt->file = NULL; + /* PK11_FreeSlot(slot); */ + + rv = SECSuccess; + +loser: + if (rv != SECSuccess) { + /* pk12u_report_failure */ + } else { + /* pk12u_report_success ? */ + } + + if (p12dcx) { + SEC_PKCS12DecoderFinish(p12dcx); + } + p12u_DestroyExportFileInfo(&p12cxt, PR_FALSE); + + if (uniPwitem.data) { + SECITEM_ZfreeItem(&uniPwitem, PR_FALSE); + } + + if (pwitem) { + SECITEM_ZfreeItem(pwitem, PR_TRUE); + } + + + return rv; +} + +static void +p12u_DoPKCS12ExportErrors() +{ + int error_value; + + error_value = PORT_GetError(); + if ((error_value == SEC_ERROR_PKCS12_UNABLE_TO_EXPORT_KEY) || + (error_value == SEC_ERROR_PKCS12_UNABLE_TO_LOCATE_OBJECT_BY_NAME) || + (error_value == SEC_ERROR_PKCS12_UNABLE_TO_WRITE)) { + fprintf(stderr, SECU_ErrorStringRaw((int16)error_value)); + } else if(error_value == SEC_ERROR_USER_CANCELLED) { + ; + } else { + fprintf(stderr, SECU_ErrorStringRaw(SEC_ERROR_EXPORTING_CERTIFICATES)); + } +} + +static void +p12u_WriteToExportFile(void *arg, const char *buf, unsigned long len) +{ + p12uContext *p12cxt = arg; + int writeLen; + + if(!p12cxt || (p12cxt->error == PR_TRUE)) { + return; + } + + if(p12cxt->file == NULL) { + p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE; + p12cxt->error = PR_TRUE; + return; + } + + writeLen = PR_Write(p12cxt->file, (unsigned char *)buf, (int32)len); + + if(writeLen != (int)len) { + PR_Close(p12cxt->file); + PR_Free(p12cxt->filename); + p12cxt->filename = NULL; + p12cxt->file = NULL; + p12cxt->errorValue = SEC_ERROR_PKCS12_UNABLE_TO_WRITE; + p12cxt->error = PR_TRUE; + } +} + +void +P12U_ExportPKCS12Object(char *nn, char *outfile, PK11SlotInfo *inSlot, + secuPWData *slotPw, secuPWData *p12FilePw) +{ + SEC_PKCS12ExportContext *p12ecx = NULL; + SEC_PKCS12SafeInfo *keySafe = NULL, *certSafe = NULL; + SECItem *pwitem = NULL; + p12uContext *p12cxt = NULL; + CERTCertList* certlist = NULL; + CERTCertListNode* node = NULL; + PK11SlotInfo* slot = NULL; + + if (P12U_InitSlot(inSlot, slotPw) != SECSuccess) { + SECU_PrintError(progName,"Failed to authenticate to \"%s\"", + PK11_GetSlotName(inSlot)); + pk12uErrno = PK12UERR_PK11GETSLOT; + goto loser; + } + certlist = PK11_FindCertsFromNickname(nn, slotPw); + if(!certlist) { + SECU_PrintError(progName,"find user certs from nickname failed"); + pk12uErrno = PK12UERR_FINDCERTBYNN; + return; + } + + if ((SECSuccess != CERT_FilterCertListForUserCerts(certlist)) || + CERT_LIST_EMPTY(certlist)) { + SECU_PrintError(progName,"no user certs from given nickname"); + pk12uErrno = PK12UERR_FINDCERTBYNN; + goto loser; + } + + /* Password to use for PKCS12 file. */ + pwitem = P12U_GetP12FilePassword(PR_TRUE, p12FilePw); + if(!pwitem) { + goto loser; + } + + p12cxt = p12u_InitFile(PR_FALSE, outfile); + if(!p12cxt) { + SECU_PrintError(progName,"Initialization failed: %s", outfile); + pk12uErrno = PK12UERR_INIT_FILE; + goto loser; + } + + if (certlist) { + CERTCertificate* cert = NULL; + node = CERT_LIST_HEAD(certlist); + if (node) { + cert = node->cert; + } + if (cert) { + slot = cert->slot; /* use the slot from the first matching + certificate to create the context . This is for keygen */ + } + } + if (!slot) { + SECU_PrintError(progName,"cert does not have a slot"); + pk12uErrno = PK12UERR_FINDCERTBYNN; + goto loser; + } + p12ecx = SEC_PKCS12CreateExportContext(NULL, NULL, slot, slotPw); + if(!p12ecx) { + SECU_PrintError(progName,"export context creation failed"); + pk12uErrno = PK12UERR_EXPORTCXCREATE; + goto loser; + } + + if(SEC_PKCS12AddPasswordIntegrity(p12ecx, pwitem, SEC_OID_SHA1) + != SECSuccess) { + SECU_PrintError(progName,"PKCS12 add password integrity failed"); + pk12uErrno = PK12UERR_PK12ADDPWDINTEG; + goto loser; + } + + for (node = CERT_LIST_HEAD(certlist);!CERT_LIST_END(node,certlist);node=CERT_LIST_NEXT(node)) + { + CERTCertificate* cert = node->cert; + if (!cert->slot) { + SECU_PrintError(progName,"cert does not have a slot"); + pk12uErrno = PK12UERR_FINDCERTBYNN; + goto loser; + } + + keySafe = SEC_PKCS12CreateUnencryptedSafe(p12ecx); + if(/*!SEC_PKCS12IsEncryptionAllowed() || */ PK11_IsFIPS()) { + certSafe = keySafe; + } else { + certSafe = SEC_PKCS12CreatePasswordPrivSafe(p12ecx, pwitem, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_40_BIT_RC2_CBC); + } + + if(!certSafe || !keySafe) { + SECU_PrintError(progName,"key or cert safe creation failed"); + pk12uErrno = PK12UERR_CERTKEYSAFE; + goto loser; + } + + if(SEC_PKCS12AddCertAndKey(p12ecx, certSafe, NULL, cert, + CERT_GetDefaultCertDB(), keySafe, NULL, PR_TRUE, pwitem, + SEC_OID_PKCS12_V2_PBE_WITH_SHA1_AND_3KEY_TRIPLE_DES_CBC) + != SECSuccess) { + SECU_PrintError(progName,"add cert and key failed"); + pk12uErrno = PK12UERR_ADDCERTKEY; + goto loser; + } + } + + CERT_DestroyCertList(certlist); + certlist = NULL; + + if(SEC_PKCS12Encode(p12ecx, p12u_WriteToExportFile, p12cxt) + != SECSuccess) { + SECU_PrintError(progName,"PKCS12 encode failed"); + pk12uErrno = PK12UERR_ENCODE; + goto loser; + } + + p12u_DestroyExportFileInfo(&p12cxt, PR_FALSE); + SECITEM_ZfreeItem(pwitem, PR_TRUE); + fprintf(stdout, "%s: PKCS12 EXPORT SUCCESSFUL\n", progName); + SEC_PKCS12DestroyExportContext(p12ecx); + + return; + +loser: + SEC_PKCS12DestroyExportContext(p12ecx); + + if (certlist) { + CERT_DestroyCertList(certlist); + certlist = NULL; + } + + if (slotPw) + PR_Free(slotPw->data); + + if (p12FilePw) + PR_Free(p12FilePw->data); + + p12u_DestroyExportFileInfo(&p12cxt, PR_TRUE); + if(pwitem) { + SECITEM_ZfreeItem(pwitem, PR_TRUE); + } + p12u_DoPKCS12ExportErrors(); + return; +} + +static void +p12u_EnableAllCiphers() +{ + SEC_PKCS12EnableCipher(PKCS12_RC4_40, 1); + SEC_PKCS12EnableCipher(PKCS12_RC4_128, 1); + SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_40, 1); + SEC_PKCS12EnableCipher(PKCS12_RC2_CBC_128, 1); + SEC_PKCS12EnableCipher(PKCS12_DES_56, 1); + SEC_PKCS12EnableCipher(PKCS12_DES_EDE3_168, 1); + SEC_PKCS12SetPreferredCipher(PKCS12_DES_EDE3_168, 1); +} + +static PRUintn +P12U_Init(char *dir, char *dbprefix) +{ + SECStatus rv; + PK11_SetPasswordFunc(SECU_GetModulePassword); + + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + rv = NSS_Initialize(dir,dbprefix,dbprefix,"secmod.db",0); + if (rv != SECSuccess) { + SECU_PrintPRandOSError(progName); + exit(-1); + } + + /* setup unicode callback functions */ + PORT_SetUCS2_ASCIIConversionFunction(p12u_ucs2_ascii_conversion_function); + /* use the defaults for UCS4-UTF8 and UCS2-UTF8 */ + + p12u_EnableAllCiphers(); + + return 0; +} + +enum { + opt_CertDir = 0, + opt_TokenName, + opt_Import, + opt_SlotPWFile, + opt_SlotPW, + opt_Nickname, + opt_Export, + opt_P12FilePWFile, + opt_P12FilePW, + opt_DBPrefix, + opt_Debug +}; + +static secuCommandFlag pk12util_options[] = +{ + { /* opt_CertDir */ 'd', PR_TRUE, 0, PR_FALSE }, + { /* opt_TokenName */ 'h', PR_TRUE, 0, PR_FALSE }, + { /* opt_Import */ 'i', PR_TRUE, 0, PR_FALSE }, + { /* opt_SlotPWFile */ 'k', PR_TRUE, 0, PR_FALSE }, + { /* opt_SlotPW */ 'K', PR_TRUE, 0, PR_FALSE }, + { /* opt_Nickname */ 'n', PR_TRUE, 0, PR_FALSE }, + { /* opt_Export */ 'o', PR_TRUE, 0, PR_FALSE }, + { /* opt_P12FilePWFile */ 'w', PR_TRUE, 0, PR_FALSE }, + { /* opt_P12FilePW */ 'W', PR_TRUE, 0, PR_FALSE }, + { /* opt_DBPrefix */ 'P', PR_TRUE, 0, PR_FALSE }, + { /* opt_Debug */ 'v', PR_FALSE, 0, PR_FALSE } +}; + +int +main(int argc, char **argv) +{ + PRIntn ret = 0; + secuPWData slotPw = { PW_NONE, NULL }; + secuPWData p12FilePw = { PW_NONE, NULL }; + PK11SlotInfo *slot; + char *slotname = NULL; + char *import_file = NULL; + char *export_file = NULL; + char *dbprefix = ""; + SECStatus rv; + + secuCommand pk12util; + pk12util.numCommands = 0; + pk12util.commands = 0; + pk12util.numOptions = sizeof(pk12util_options) / sizeof(secuCommandFlag); + pk12util.options = pk12util_options; + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + rv = SECU_ParseCommandLine(argc, argv, progName, &pk12util); + + if (rv != SECSuccess) + Usage(progName); + + pk12_debugging = pk12util.options[opt_Debug].activated; + + if (pk12util.options[opt_Import].activated && + pk12util.options[opt_Export].activated) { + Usage(progName); + } + + if (pk12util.options[opt_Export].activated && + !pk12util.options[opt_Nickname].activated) { + Usage(progName); + } + + slotname = SECU_GetOptionArg(&pk12util, opt_TokenName); + import_file = SECU_GetOptionArg(&pk12util, opt_Import); + export_file = SECU_GetOptionArg(&pk12util, opt_Export); + + if (pk12util.options[opt_P12FilePWFile].activated) { + p12FilePw.source = PW_FROMFILE; + p12FilePw.data = PL_strdup(pk12util.options[opt_P12FilePWFile].arg); + } + + if (pk12util.options[opt_P12FilePW].activated) { + p12FilePw.source = PW_PLAINTEXT; + p12FilePw.data = PL_strdup(pk12util.options[opt_P12FilePW].arg); + } + + if (pk12util.options[opt_SlotPWFile].activated) { + slotPw.source = PW_FROMFILE; + slotPw.data = PL_strdup(pk12util.options[opt_SlotPWFile].arg); + } + + if (pk12util.options[opt_SlotPW].activated) { + slotPw.source = PW_PLAINTEXT; + slotPw.data = PL_strdup(pk12util.options[opt_SlotPW].arg); + } + + if (pk12util.options[opt_CertDir].activated) { + SECU_ConfigDirectory(pk12util.options[opt_CertDir].arg); + } + if (pk12util.options[opt_DBPrefix].activated) { + dbprefix = pk12util.options[opt_DBPrefix].arg; + } + P12U_Init(SECU_ConfigDirectory(NULL),dbprefix); + + if (!slotname || PL_strcmp(slotname, "internal") == 0) + slot = PK11_GetInternalKeySlot(); + else + slot = PK11_FindSlotByName(slotname); + + if (!slot) { + SECU_PrintError(progName,"Invalid slot \"%s\"", slotname); + pk12uErrno = PK12UERR_PK11GETSLOT; + goto done; + } + + if (pk12util.options[opt_Import].activated) { + + if ((ret = P12U_ImportPKCS12Object(import_file, slot, &slotPw, + &p12FilePw)) != 0) + goto done; + + } else if (pk12util.options[opt_Export].activated) { + P12U_ExportPKCS12Object(pk12util.options[opt_Nickname].arg, + export_file, slot, &slotPw, &p12FilePw); + } else { + Usage(progName); + pk12uErrno = PK12UERR_USAGE; + } + +done: + if (slot) PK11_FreeSlot(slot); + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + exit(pk12uErrno); +} diff --git a/security/nss/cmd/pk12util/pk12util.h b/security/nss/cmd/pk12util/pk12util.h new file mode 100644 index 000000000..8e456d98c --- /dev/null +++ b/security/nss/cmd/pk12util/pk12util.h @@ -0,0 +1,69 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* + * ERROR codes in pk12util + * - should be organized better later + */ +#define PK12UERR_USER_CANCELLED 1 +#define PK12UERR_USAGE 2 +#define PK12UERR_CERTDB_OPEN 8 +#define PK12UERR_KEYDB_OPEN 9 +#define PK12UERR_INIT_FILE 10 +#define PK12UERR_UNICODECONV 11 +#define PK12UERR_TMPDIGCREATE 12 +#define PK12UERR_PK11GETSLOT 13 +#define PK12UERR_PK12DECODESTART 14 +#define PK12UERR_IMPORTFILEREAD 15 +#define PK12UERR_DECODE 16 +#define PK12UERR_DECODEVERIFY 17 +#define PK12UERR_DECODEVALIBAGS 18 +#define PK12UERR_DECODEIMPTBAGS 19 +#define PK12UERR_CERTALREADYEXISTS 20 +#define PK12UERR_PATCHDB 22 +#define PK12UERR_GETDEFCERTDB 23 +#define PK12UERR_FINDCERTBYNN 24 +#define PK12UERR_EXPORTCXCREATE 25 +#define PK12UERR_PK12ADDPWDINTEG 26 +#define PK12UERR_CERTKEYSAFE 27 +#define PK12UERR_ADDCERTKEY 28 +#define PK12UERR_ENCODE 29 + + +/* additions for importing and exporting PKCS 12 files */ +typedef struct p12uContextStr { + char *filename; /* name of file */ + PRFileDesc *file; /* pointer to file */ + PRBool error; /* error occurred? */ + int errorValue; /* which error occurred? */ +} p12uContext; diff --git a/security/nss/cmd/pkiutil/Makefile b/security/nss/cmd/pkiutil/Makefile new file mode 100644 index 000000000..23afa3799 --- /dev/null +++ b/security/nss/cmd/pkiutil/Makefile @@ -0,0 +1,76 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include platlibs.mk + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/pkiutil/manifest.mn b/security/nss/cmd/pkiutil/manifest.mn new file mode 100644 index 000000000..3f65c29ab --- /dev/null +++ b/security/nss/cmd/pkiutil/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +CSRCS = \ + pkiutil.c \ + $(NULL) + +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = dbm seccmd + +PROGRAM = pkiutil diff --git a/security/nss/cmd/pkiutil/pkiutil.c b/security/nss/cmd/pkiutil/pkiutil.c new file mode 100644 index 000000000..f922debab --- /dev/null +++ b/security/nss/cmd/pkiutil/pkiutil.c @@ -0,0 +1,373 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "prtypes.h" +#include "prtime.h" +#include "prlong.h" +#include "nss.h" +#include "cmdutil.h" +#include "nsspki.h" +/* hmmm...*/ +#include "pki.h" + +#define PKIUTIL_VERSION_STRING "pkiutil version 0.1" + +char *progName = NULL; + +typedef struct { + PRBool raw; + PRBool ascii; + char *name; + PRFileDesc *file; +} objOutputMode; + +typedef enum { + PKIUnknown = -1, + PKICertificate, + PKIPublicKey, + PKIPrivateKey, + PKIAny +} PKIObjectType; + +static PKIObjectType +get_object_class(char *type) +{ + if (strcmp(type, "certificate") == 0 || strcmp(type, "cert") == 0 || + strcmp(type, "Certificate") == 0 || strcmp(type, "Cert") == 0) { + return PKICertificate; + } else if (strcmp(type, "public_key") == 0 || + strcmp(type, "PublicKey") == 0) { + return PKIPublicKey; + } else if (strcmp(type, "private_key") == 0 || + strcmp(type, "PrivateKey") == 0) { + return PKIPrivateKey; + } else if (strcmp(type, "all") == 0 || strcmp(type, "any") == 0) { + return PKIAny; + } + fprintf(stderr, "%s: \"%s\" is not a valid PKCS#11 object type.\n", + progName, type); + return PKIUnknown; +} + +static PRStatus +print_cert_callback(NSSCertificate *c, void *arg) +{ + int i; + NSSUTF8 *label; + NSSItem *id; + label = NSSCertificate_GetLabel(c); + printf("%s\n", label); + nss_ZFreeIf((void*)label); +#if 0 + id = NSSCertificate_GetID(c); + for (i=0; i<id->size; i++) { + printf("%c", ((char *)id->data)[i]); + } + printf("\n"); +#endif + return PR_SUCCESS; +} + +/* pkiutil commands */ +enum { + cmd_Add = 0, + cmd_Dump, + cmd_List, + cmd_Version, + pkiutil_num_commands +}; + +/* pkiutil options */ +enum { + opt_Help = 0, + opt_Ascii, + opt_ProfileDir, + opt_TokenName, + opt_InputFile, + opt_Nickname, + opt_OutputFile, + opt_Binary, + opt_Trust, + opt_Type, + pkiutil_num_options +}; + +static cmdCommandLineArg pkiutil_commands[] = +{ + { /* cmd_Add */ 'A', "add", CMDNoArg, 0, PR_FALSE, + CMDBIT(opt_Nickname) | CMDBIT(opt_Trust), + CMDBIT(opt_Ascii) | CMDBIT(opt_ProfileDir) + | CMDBIT(opt_TokenName) | CMDBIT(opt_InputFile) + | CMDBIT(opt_Binary) | CMDBIT(opt_Type) }, + { /* cmd_Dump */ 0 , "dump", CMDNoArg, 0, PR_FALSE, + CMDBIT(opt_Nickname), + CMDBIT(opt_Ascii) | CMDBIT(opt_ProfileDir) + | CMDBIT(opt_TokenName) | CMDBIT(opt_Binary) + | CMDBIT(opt_Type) }, + { /* cmd_List */ 'L', "list", CMDNoArg, 0, PR_FALSE, 0, + CMDBIT(opt_Ascii) | CMDBIT(opt_ProfileDir) + | CMDBIT(opt_TokenName) | CMDBIT(opt_Binary) + | CMDBIT(opt_Nickname) | CMDBIT(opt_Type) }, + { /* cmd_Version */ 'Y', "version", CMDNoArg, 0, PR_FALSE, 0, 0 } +}; + +static cmdCommandLineOpt pkiutil_options[] = +{ + { /* opt_Help */ '?', "help", CMDNoArg, 0, PR_FALSE }, + { /* opt_Ascii */ 'a', "ascii", CMDNoArg, 0, PR_FALSE }, + { /* opt_ProfileDir */ 'd', "dbdir", CMDArgReq, 0, PR_FALSE }, + { /* opt_TokenName */ 'h', "token", CMDArgReq, 0, PR_FALSE }, + { /* opt_InputFile */ 'i', "infile", CMDArgReq, 0, PR_FALSE }, + { /* opt_Nickname */ 'n', "nickname", CMDArgReq, 0, PR_FALSE }, + { /* opt_OutputFile */ 'o', "outfile", CMDArgReq, 0, PR_FALSE }, + { /* opt_Binary */ 'r', "raw", CMDNoArg, 0, PR_FALSE }, + { /* opt_Trust */ 't', "trust", CMDArgReq, 0, PR_FALSE }, + { /* opt_Type */ 0 , "type", CMDArgReq, 0, PR_FALSE } +}; + +void pkiutil_usage(cmdPrintState *ps, + int num, PRBool cmd, PRBool header, PRBool footer) +{ +#define pusg CMD_PrintUsageString + if (header) { + pusg(ps, "utility for managing PKCS#11 objects (certs and keys)\n"); + } else if (footer) { + /* + printf("certificate trust can be:\n"); + printf(" p - valid peer, P - trusted peer (implies p)\n"); + printf(" c - valid CA\n"); + printf(" T - trusted CA to issue client certs (implies c)\n"); + printf(" C - trusted CA to issue server certs (implies c)\n"); + printf(" u - user cert\n"); + printf(" w - send warning\n"); + */ + } else if (cmd) { + switch(num) { + case cmd_Add: + pusg(ps, "Add an object to the token"); break; + case cmd_Dump: + pusg(ps, "Dump a single object"); break; + case cmd_List: + pusg(ps, "List objects on the token (-n for single object)"); break; + case cmd_Version: + pusg(ps, "Report version"); break; + default: + pusg(ps, "Unrecognized command"); break; + } + } else { + switch(num) { + case opt_Ascii: + pusg(ps, "Use ascii (base-64 encoded) mode for I/O"); break; + case opt_ProfileDir: + pusg(ps, "Directory containing security databases (def: \".\")"); + break; + case opt_TokenName: + pusg(ps, "Name of PKCS#11 token to use (def: internal)"); break; + case opt_InputFile: + pusg(ps, "File for input (def: stdin)"); break; + case opt_Nickname: + pusg(ps, "Nickname of object"); break; + case opt_OutputFile: + pusg(ps, "File for output (def: stdout)"); break; + case opt_Binary: + pusg(ps, "Use raw (binary der-encoded) mode for I/O"); break; + case opt_Trust: + pusg(ps, "Trust level for certificate"); break; + case opt_Help: break; + default: + pusg(ps, "Unrecognized option"); + } + } +} + +int +main(int argc, char **argv) +{ + PRFileDesc *infile = NULL; + PRFileDesc *outfile = NULL; + char *profiledir = "./"; +#if 0 + secuPWData pwdata = { PW_NONE, 0 }; +#endif + int objclass = 3; /* ANY */ + NSSTrustDomain *root_cert_td = NULL; + char *rootpath = NULL; + char builtin_name[]= "libnssckbi.so"; /* temporary hardcode */ + PRStatus rv = PR_SUCCESS; + + int cmdToRun; + cmdCommand pkiutil; + pkiutil.ncmd = pkiutil_num_commands; + pkiutil.nopt = pkiutil_num_options; + pkiutil.cmd = pkiutil_commands; + pkiutil.opt = pkiutil_options; + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + cmdToRun = CMD_ParseCommandLine(argc, argv, progName, &pkiutil); + +#if 0 + { int i, nc; + for (i=0; i<pkiutil.ncmd; i++) + printf("%s: %s <%s>\n", pkiutil.cmd[i].s, + (pkiutil.cmd[i].on) ? "on" : "off", + pkiutil.cmd[i].arg); + for (i=0; i<pkiutil.nopt; i++) + printf("%s: %s <%s>\n", pkiutil.opt[i].s, + (pkiutil.opt[i].on) ? "on" : "off", + pkiutil.opt[i].arg); + } +#endif + + if (pkiutil.opt[opt_Help].on) + CMD_LongUsage(progName, &pkiutil, pkiutil_usage); + + if (cmdToRun < 0) + CMD_Usage(progName, &pkiutil); + + /* -d */ + if (pkiutil.opt[opt_ProfileDir].on) { + profiledir = strdup(pkiutil.opt[opt_ProfileDir].arg); + } + + /* -i */ + if (pkiutil.opt[opt_InputFile].on) { + char *fn = pkiutil.opt[opt_InputFile].arg; + infile = PR_Open(fn, PR_RDONLY, 0660); + } else { + infile = PR_STDIN; + } + + /* -o */ + if (pkiutil.opt[opt_OutputFile].on) { + char *fn = pkiutil.opt[opt_OutputFile].arg; + outfile = PR_Open(fn, PR_WRONLY | PR_CREATE_FILE, 0660); + } else { + outfile = PR_STDOUT; + } + + /* --type can be found on many options */ + if (pkiutil.opt[opt_Type].on) + objclass = get_object_class(pkiutil.opt[opt_Type].arg); + else if (cmdToRun == cmd_Dump && pkiutil.cmd[cmd_Dump].arg) + objclass = get_object_class(pkiutil.cmd[cmd_Dump].arg); + else if (cmdToRun == cmd_List && pkiutil.cmd[cmd_List].arg) + objclass = get_object_class(pkiutil.cmd[cmd_List].arg); + else if (cmdToRun == cmd_Add && pkiutil.cmd[cmd_Add].arg) + objclass = get_object_class(pkiutil.cmd[cmd_Add].arg); + if (objclass < 0) + goto done; + + /* --print is an alias for --list --nickname */ + if (cmdToRun == cmd_Dump) cmdToRun = cmd_List; + + /* if list has raw | ascii must have -n. can't have both raw and ascii */ + if (pkiutil.opt[opt_Binary].on || pkiutil.opt[opt_Ascii].on) { + if (cmdToRun == cmd_List && !pkiutil.opt[opt_Nickname].on) { + fprintf(stderr, "%s: specify a object to output with -n\n", + progName); + CMD_LongUsage(progName, &pkiutil, pkiutil_usage); + } + } + + /* initialize */ + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + /* NSS_InitReadWrite(profiledir); */ + NSS_NoDB_Init(NULL); + + /* Display version info and exit */ + if (cmdToRun == cmd_Version) { + printf("%s\nNSS Version %s\n", PKIUTIL_VERSION_STRING, NSS_VERSION); + goto done; + } + + /* XXX okay - bootstrap stan by loading the root cert module for testing */ + root_cert_td = NSSTrustDomain_Create(NULL, NULL, NULL, NULL); + { + int rootpathlen = strlen(profiledir) + strlen(builtin_name) + 1; + rootpath = (char *)malloc(rootpathlen); + memcpy(rootpath, profiledir, strlen(profiledir)); + memcpy(rootpath + strlen(profiledir), + builtin_name, strlen(builtin_name)); + rootpath[rootpathlen - 1] = '\0'; + } + NSSTrustDomain_LoadModule(root_cert_td, "Builtin Root Module", rootpath, + NULL, NULL); + + printf("\n"); + if (pkiutil.opt[opt_Nickname].on) { + int i; + NSSCertificate **certs; + NSSCertificate *cert; + certs = NSSTrustDomain_FindCertificatesByNickname(root_cert_td, + pkiutil.opt[opt_Nickname].arg, NULL, 0, NULL); + i = 0; + while ((cert = certs[i++]) != NULL) { + printf("Found cert:\n"); + print_cert_callback(cert, NULL); + } + } else { + NSSTrustDomain_TraverseCertificates(root_cert_td, print_cert_callback, 0); + } + + NSSTrustDomain_Destroy(root_cert_td); + + /* List token objects */ + if (cmdToRun == cmd_List) { +#if 0 + rv = list_token_objects(slot, objclass, + pkiutil.opt[opt_Nickname].arg, + pkiutil.opt[opt_Binary].on, + pkiutil.opt[opt_Ascii].on, + outfile, &pwdata); +#endif + goto done; + } + +#if 0 + /* Import an object into the token. */ + if (cmdToRun == cmd_Add) { + rv = add_object_to_token(slot, object); + goto done; + } +#endif + +done: + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + + return rv; +} diff --git a/security/nss/cmd/pkiutil/platlibs.mk b/security/nss/cmd/pkiutil/platlibs.mk new file mode 100644 index 000000000..9a714f300 --- /dev/null +++ b/security/nss/cmd/pkiutil/platlibs.mk @@ -0,0 +1,53 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +# $(PROGRAM) has explicit dependencies on $(EXTRA_LIBS) +EXTRA_LIBS += \ + $(DIST)/lib/libcmdutil.$(LIB_SUFFIX) \ + $(NULL) + +ifeq ($(OS_ARCH), AIX) +EXTRA_SHARED_LIBS += -brtl +endif + +# $(PROGRAM) has NO explicit dependencies on $(EXTRA_SHARED_LIBS) +# $(EXTRA_SHARED_LIBS) come before $(OS_LIBS), except on AIX. +EXTRA_SHARED_LIBS += \ + -L$(DIST)/lib/ \ + -lnsspki3 \ + -lnss3 \ + -lplc4 \ + -lplds4 \ + -lnspr4 \ + $(NULL) + diff --git a/security/nss/cmd/platlibs.mk b/security/nss/cmd/platlibs.mk new file mode 100644 index 000000000..a160c3176 --- /dev/null +++ b/security/nss/cmd/platlibs.mk @@ -0,0 +1,219 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 USE_STATIC_LIBS + +# can't do this in manifest.mn because OS_ARCH isn't defined there. +ifeq ($(OS_ARCH), WINNT) + +DEFINES += -DNSS_USE_STATIC_LIBS +# $(PROGRAM) has explicit dependencies on $(EXTRA_LIBS) +CRYPTOLIB=$(DIST)/lib/$(LIB_PREFIX)freebl.$(LIB_SUFFIX) +ifdef MOZILLA_SECURITY_BUILD + CRYPTOLIB=$(DIST)/lib/crypto.lib +endif +ifdef MOZILLA_BSAFE_BUILD + CRYPTOLIB+=$(DIST)/lib/bsafe$(BSAFEVER).lib + CRYPTOLIB+=$(DIST)/lib/freebl.lib +endif + +EXTRA_LIBS += \ + $(DIST)/lib/$(LIB_PREFIX)smime.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)ssl.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)nss.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)ssl.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)sectool.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)pkcs12.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)pkcs7.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)certhi.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)cryptohi.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)pk11wrap.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)certdb.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)softokn.$(LIB_SUFFIX) \ + $(CRYPTOLIB) \ + $(DIST)/lib/$(LIB_PREFIX)swfci.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)secutil.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)nsspki.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)nssdev.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)nssb.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)dbm.$(LIB_SUFFIX) \ + $(DIST)/lib/$(NSPR31_LIB_PREFIX)plc4.$(LIB_SUFFIX) \ + $(DIST)/lib/$(NSPR31_LIB_PREFIX)plds4.$(LIB_SUFFIX) \ + $(DIST)/lib/$(NSPR31_LIB_PREFIX)nspr4.$(LIB_SUFFIX) \ + $(NULL) + +# $(PROGRAM) has NO explicit dependencies on $(OS_LIBS) +#OS_LIBS += \ + wsock32.lib \ + winmm.lib \ + $(NULL) + +JAR_LIBS = $(DIST)/lib/$(LIB_PREFIX)jar.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)zlib.$(LIB_SUFFIX) \ + $(NULL) +else + +# $(PROGRAM) has explicit dependencies on $(EXTRA_LIBS) +CRYPTOLIB=$(DIST)/lib/$(LIB_PREFIX)freebl.$(LIB_SUFFIX) +ifdef MOZILLA_SECURITY_BUILD + CRYPTOLIB=$(DIST)/lib/$(LIB_PREFIX)crypto.$(LIB_SUFFIX) +endif +ifdef MOZILLA_BSAFE_BUILD + CRYPTOLIB+=$(DIST)/lib/$(LIB_PREFIX)bsafe.$(LIB_SUFFIX) + CRYPTOLIB+=$(DIST)/lib/$(LIB_PREFIX)freebl.$(LIB_SUFFIX) +endif +EXTRA_LIBS += \ + $(DIST)/lib/$(LIB_PREFIX)smime.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)ssl.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)nss.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)ssl.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)sectool.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)pkcs12.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)pkcs7.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)certhi.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)pk11wrap.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)cryptohi.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)certhi.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)nsspki.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)pk11wrap.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)softokn.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)certdb.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)nsspki.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)nssdev.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)nssb.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)swfci.$(LIB_SUFFIX) \ + $(CRYPTOLIB) \ + $(DIST)/lib/$(LIB_PREFIX)secutil.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)dbm.$(LIB_SUFFIX) \ + $(NULL) + +ifeq ($(OS_ARCH), AIX) +EXTRA_SHARED_LIBS += -brtl +endif + +# $(PROGRAM) has NO explicit dependencies on $(EXTRA_SHARED_LIBS) +# $(EXTRA_SHARED_LIBS) come before $(OS_LIBS), except on AIX. +ifdef XP_OS2_VACPP +EXTRA_SHARED_LIBS += \ + $(DIST)/lib/plc4.lib \ + $(DIST)/lib/plds4.lib \ + $(DIST)/lib/nspr4.lib \ + $(NULL) +else +EXTRA_SHARED_LIBS += \ + -L$(DIST)/lib \ + -lplc4 \ + -lplds4 \ + -lnspr4 \ + $(NULL) +endif +endif + +JAR_LIBS = $(DIST)/lib/$(LIB_PREFIX)jar.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)zlib.$(LIB_SUFFIX) \ + $(NULL) + +else # USE_STATIC_LIBS +# can't do this in manifest.mn because OS_ARCH isn't defined there. +ifeq ($(OS_ARCH), WINNT) + +# $(PROGRAM) has explicit dependencies on $(EXTRA_LIBS) +EXTRA_LIBS += \ + $(DIST)/lib/$(LIB_PREFIX)sectool.$(LIB_SUFFIX) \ + $(DIST)/lib/$(IMPORT_LIB_PREFIX)smime3$(IMPORT_LIB_SUFFIX) \ + $(DIST)/lib/$(IMPORT_LIB_PREFIX)ssl3$(IMPORT_LIB_SUFFIX) \ + $(DIST)/lib/$(IMPORT_LIB_PREFIX)nss3$(IMPORT_LIB_SUFFIX) \ + $(DIST)/lib/$(NSPR31_LIB_PREFIX)plc4.$(LIB_SUFFIX) \ + $(DIST)/lib/$(NSPR31_LIB_PREFIX)plds4.$(LIB_SUFFIX) \ + $(DIST)/lib/$(NSPR31_LIB_PREFIX)nspr4.$(LIB_SUFFIX) \ + $(NULL) + +# $(PROGRAM) has NO explicit dependencies on $(OS_LIBS) +#OS_LIBS += \ + wsock32.lib \ + winmm.lib \ + $(NULL) + +JAR_LIBS = $(DIST)/lib/$(LIB_PREFIX)jar.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)zlib.$(LIB_SUFFIX) \ + $(NULL) +else + +# $(PROGRAM) has explicit dependencies on $(EXTRA_LIBS) +EXTRA_LIBS += \ + $(DIST)/lib/$(LIB_PREFIX)sectool.$(LIB_SUFFIX) \ + $(NULL) + +ifeq ($(OS_ARCH), AIX) +EXTRA_SHARED_LIBS += -brtl +endif + +# If GNU ld is used, we must use the -rpath-link option to tell +# the linker where to find libsoftokn3.so, an implicit dependency +# of libnss3.so. +ifeq (,$(filter-out BSD_OS FreeBSD Linux NetBSD, $(OS_ARCH))) +EXTRA_SHARED_LIBS += -Wl,-rpath-link,$(DIST)/lib +endif + +ifeq ($(OS_ARCH), SunOS) +ifdef NS_USE_GCC +ifdef GCC_USE_GNU_LD +EXTRA_SHARED_LIBS += -Wl,-rpath-link,$(DIST)/lib +endif +endif +endif + +ifeq ($(OS_ARCH), Darwin) +EXTRA_SHARED_LIBS += -dylib_file @executable_path/libsoftokn3.dylib:$(DIST)/lib/libsoftokn3.dylib +endif + + +# $(PROGRAM) has NO explicit dependencies on $(EXTRA_SHARED_LIBS) +# $(EXTRA_SHARED_LIBS) come before $(OS_LIBS), except on AIX. +EXTRA_SHARED_LIBS += \ + -L$(DIST)/lib \ + -lssl3 \ + -lsmime3 \ + -lnss3 \ + -lplc4 \ + -lplds4 \ + -lnspr4 \ + $(NULL) + +JAR_LIBS = $(DIST)/lib/$(LIB_PREFIX)jar.$(LIB_SUFFIX) \ + $(DIST)/lib/$(LIB_PREFIX)zlib.$(LIB_SUFFIX) \ + $(NULL) +endif + +endif # USE_STATIC_LIBS diff --git a/security/nss/cmd/platrules.mk b/security/nss/cmd/platrules.mk new file mode 100644 index 000000000..3e5c19933 --- /dev/null +++ b/security/nss/cmd/platrules.mk @@ -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. +# + +show: + @echo "DEFINES = ${DEFINES}" + @echo "EXTRA_LIBS = >$(EXTRA_LIBS)<" + @echo "IMPORT_LIBRARY = $(IMPORT_LIBRARY)" + @echo "LIBRARY = $(LIBRARY)" + @echo "OBJS = $(OBJS)" + @echo "OS_ARCH = $(OS_ARCH)" + @echo "PROGRAM = >$(PROGRAM)<" + @echo "PROGRAMS = $(PROGRAMS)" + @echo "SHARED_LIBRARY = $(SHARED_LIBRARY)" + @echo "TARGETS = >$(TARGETS)<" + +showplatform: + @echo $(PLATFORM) diff --git a/security/nss/cmd/pp/Makefile b/security/nss/cmd/pp/Makefile new file mode 100644 index 000000000..4e39ffc3f --- /dev/null +++ b/security/nss/cmd/pp/Makefile @@ -0,0 +1,75 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/pp/manifest.mn b/security/nss/cmd/pp/manifest.mn new file mode 100644 index 000000000..f43c9c625 --- /dev/null +++ b/security/nss/cmd/pp/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +# This next line is used by .mk files +# and gets translated into $LINCS in manifest.mnw +REQUIRES = seccmd dbm + +DEFINES = -DNSPR20 + +CSRCS = pp.c + +PROGRAM = pp diff --git a/security/nss/cmd/pp/pp.c b/security/nss/cmd/pp/pp.c new file mode 100644 index 000000000..157dec0af --- /dev/null +++ b/security/nss/cmd/pp/pp.c @@ -0,0 +1,176 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* + * Pretty-print some well-known BER or DER encoded data (e.g. certificates, + * keys, pkcs7) + * + * $Id$ + */ + +#include "secutil.h" + +#if defined(__sun) && !defined(SVR4) +extern int fprintf(FILE *, char *, ...); +#endif + +#include "plgetopt.h" + +#include "pk11func.h" +#include "nspr.h" +#include "nss.h" + +static void Usage(char *progName) +{ + fprintf(stderr, + "Usage: %s -t type [-a] [-i input] [-o output]\n", + progName); + fprintf(stderr, "%-20s Specify the input type (must be one of %s,\n", + "-t type", SEC_CT_PRIVATE_KEY); + fprintf(stderr, "%-20s %s, %s, %s,\n", "", SEC_CT_PUBLIC_KEY, + SEC_CT_CERTIFICATE, SEC_CT_CERTIFICATE_REQUEST); + fprintf(stderr, "%-20s %s or %s)\n", "", SEC_CT_PKCS7, SEC_CT_CRL); + fprintf(stderr, "%-20s Input is in ascii encoded form (RFC1113)\n", + "-a"); + fprintf(stderr, "%-20s Define an input file to use (default is stdin)\n", + "-i input"); + fprintf(stderr, "%-20s Define an output file to use (default is stdout)\n", + "-o output"); + exit(-1); +} + +int main(int argc, char **argv) +{ + int rv, ascii; + char *progName; + FILE *outFile; + PRFileDesc *inFile; + SECItem der, data; + char *typeTag; + PLOptState *optstate; + + progName = strrchr(argv[0], '/'); + progName = progName ? progName+1 : argv[0]; + + ascii = 0; + inFile = 0; + outFile = 0; + typeTag = 0; + optstate = PL_CreateOptState(argc, argv, "at:i:o:"); + while ( PL_GetNextOpt(optstate) == PL_OPT_OK ) { + switch (optstate->option) { + case '?': + Usage(progName); + break; + + case 'a': + ascii = 1; + break; + + case 'i': + inFile = PR_Open(optstate->value, PR_RDONLY, 0); + if (!inFile) { + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", + progName, optstate->value); + return -1; + } + break; + + case 'o': + outFile = fopen(optstate->value, "w"); + if (!outFile) { + fprintf(stderr, "%s: unable to open \"%s\" for writing\n", + progName, optstate->value); + return -1; + } + break; + + case 't': + typeTag = strdup(optstate->value); + break; + } + } + + if (!typeTag) Usage(progName); + + if (!inFile) inFile = PR_STDIN; + if (!outFile) outFile = stdout; + + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + rv = NSS_NoDB_Init(NULL); + if (rv != SECSuccess) { + fprintf(stderr, "%s: NSS_NoDB_Init failed\n", progName); + exit(1); + } + + rv = SECU_ReadDERFromFile(&der, inFile, ascii); + if (rv != SECSuccess) { + fprintf(stderr, "%s: SECU_ReadDERFromFile failed\n", progName); + exit(1); + } + + /* Data is untyped, using the specified type */ + data.data = der.data; + data.len = der.len; + + /* Pretty print it */ + if (PORT_Strcmp(typeTag, SEC_CT_CERTIFICATE) == 0) { + rv = SECU_PrintSignedData(outFile, &data, "Certificate", 0, + SECU_PrintCertificate); + } else if (PORT_Strcmp(typeTag, SEC_CT_CERTIFICATE_REQUEST) == 0) { + rv = SECU_PrintSignedData(outFile, &data, "Certificate Request", 0, + SECU_PrintCertificateRequest); + } else if (PORT_Strcmp (typeTag, SEC_CT_CRL) == 0) { + rv = SECU_PrintSignedData (outFile, &data, "CRL", 0, SECU_PrintCrl); +#ifdef HAVE_EPV_TEMPLATE + } else if (PORT_Strcmp(typeTag, SEC_CT_PRIVATE_KEY) == 0) { + rv = SECU_PrintPrivateKey(outFile, &data, "Private Key", 0); +#endif + } else if (PORT_Strcmp(typeTag, SEC_CT_PUBLIC_KEY) == 0) { + rv = SECU_PrintPublicKey(outFile, &data, "Public Key", 0); + } else if (PORT_Strcmp(typeTag, SEC_CT_PKCS7) == 0) { + rv = SECU_PrintPKCS7ContentInfo(outFile, &data, + "PKCS #7 Content Info", 0); + } else { + fprintf(stderr, "%s: don't know how to print out '%s' files\n", + progName, typeTag); + return -1; + } + + if (rv) { + fprintf(stderr, "%s: problem converting data (%s)\n", + progName, SECU_Strerror(PORT_GetError())); + return -1; + } + return 0; +} diff --git a/security/nss/cmd/rsaperf/Makefile b/security/nss/cmd/rsaperf/Makefile new file mode 100644 index 000000000..35dc5f5da --- /dev/null +++ b/security/nss/cmd/rsaperf/Makefile @@ -0,0 +1,84 @@ +#! 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) 1998-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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### +include ../platlibs.mk + +ifeq (,$(filter-out WINNT WIN95 WIN16,$(OS_TARGET))) #omits WINCE +ifndef BUILD_OPT +ifndef NS_USE_GCC +LDFLAGS += /subsystem:console /profile /debug /machine:I386 /incremental:no +endif +OS_CFLAGS += -D_CONSOLE +endif +endif + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/rsaperf/defkey.c b/security/nss/cmd/rsaperf/defkey.c new file mode 100644 index 000000000..3dd4fe36c --- /dev/null +++ b/security/nss/cmd/rsaperf/defkey.c @@ -0,0 +1,202 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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) 1998-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. + */ + +/* This key is the 1024-bit test key used for speed testing of RSA private +** key ops. +*/ +#include "seccomon.h" +#include "secoidt.h" +#include "lowkeyti.h" + +#undef CONST +#define CONST + +static CONST unsigned char default_n[128] = { +0xc2,0xae,0x96,0x89,0xaf,0xce,0xd0,0x7b,0x3b,0x35,0xfd,0x0f,0xb1,0xf4,0x7a,0xd1, +0x3c,0x7d,0xb5,0x86,0xf2,0x68,0x36,0xc9,0x97,0xe6,0x82,0x94,0x86,0xaa,0x05,0x39, +0xec,0x11,0x51,0xcc,0x5c,0xa1,0x59,0xba,0x29,0x18,0xf3,0x28,0xf1,0x9d,0xe3,0xae, +0x96,0x5d,0x6d,0x87,0x73,0xf6,0xf6,0x1f,0xd0,0x2d,0xfb,0x2f,0x7a,0x13,0x7f,0xc8, +0x0c,0x7a,0xe9,0x85,0xfb,0xce,0x74,0x86,0xf8,0xef,0x2f,0x85,0x37,0x73,0x0f,0x62, +0x4e,0x93,0x17,0xb7,0x7e,0x84,0x9a,0x94,0x11,0x05,0xca,0x0d,0x31,0x4b,0x2a,0xc8, +0xdf,0xfe,0xe9,0x0c,0x13,0xc7,0xf2,0xad,0x19,0x64,0x28,0x3c,0xb5,0x6a,0xc8,0x4b, +0x79,0xea,0x7c,0xce,0x75,0x92,0x45,0x3e,0xa3,0x9d,0x64,0x6f,0x04,0x69,0x19,0x17 +}; + +static CONST unsigned char default_e[3] = { 0x01,0x00,0x01 }; + +static CONST unsigned char default_d[128] = { +0x13,0xcb,0xbc,0xf2,0xf3,0x35,0x8c,0x6d,0x7b,0x6f,0xd9,0xf3,0xa6,0x9c,0xbd,0x80, +0x59,0x2e,0x4f,0x2f,0x11,0xa7,0x17,0x2b,0x18,0x8f,0x0f,0xe8,0x1a,0x69,0x5f,0x6e, +0xac,0x5a,0x76,0x7e,0xd9,0x4c,0x6e,0xdb,0x47,0x22,0x8a,0x57,0x37,0x7a,0x5e,0x94, +0x7a,0x25,0xb5,0xe5,0x78,0x1d,0x3c,0x99,0xaf,0x89,0x7d,0x69,0x2e,0x78,0x9d,0x1d, +0x84,0xc8,0xc1,0xd7,0x1a,0xb2,0x6d,0x2d,0x8a,0xd9,0xab,0x6b,0xce,0xae,0xb0,0xa0, +0x58,0x55,0xad,0x5c,0x40,0x8a,0xd6,0x96,0x08,0x8a,0xe8,0x63,0xe6,0x3d,0x6c,0x20, +0x49,0xc7,0xaf,0x0f,0x25,0x73,0xd3,0x69,0x43,0x3b,0xf2,0x32,0xf8,0x3d,0x5e,0xee, +0x7a,0xca,0xd6,0x94,0x55,0xe5,0xbd,0x25,0x34,0x8d,0x63,0x40,0xb5,0x8a,0xc3,0x01 +}; + +static CONST unsigned char default_p[64] = { +0xf6,0x3c,0x3f,0x56,0x58,0x4f,0xb3,0x82,0x0c,0xf0,0x5b,0x42,0x36,0x1c,0x93,0xde, +0x9b,0x32,0x01,0xb1,0x48,0xf8,0x00,0x57,0x9b,0xc1,0xbe,0x66,0xc2,0xbb,0xea,0x7c, +0x75,0x29,0x2c,0x22,0xaa,0x7c,0xaf,0xbd,0x0d,0x3f,0xb0,0x64,0x97,0xf0,0x88,0x25, +0xcb,0x8d,0xc7,0x19,0x0a,0x75,0x44,0xa4,0x5a,0xc3,0xb5,0xb9,0x85,0xea,0x27,0xa7 +}; + +static CONST unsigned char default_q[64] = { +0xca,0x66,0xfa,0x18,0x6a,0x46,0x36,0x1c,0x46,0xfe,0x47,0xe9,0x7e,0x52,0x83,0x8a, +0xbb,0x72,0x13,0xcc,0x83,0x56,0x3d,0x64,0x22,0xdd,0xfa,0x7c,0x61,0x99,0xea,0xa4, +0xb3,0x0e,0x8f,0x79,0x10,0xab,0xba,0x4a,0x73,0xd1,0x48,0x40,0x34,0x34,0xd3,0xd2, +0x54,0x92,0xbe,0xf5,0xc8,0xc4,0x60,0x5f,0xd3,0xf7,0xce,0xbe,0x60,0x3e,0xb1,0x11 +}; + +static CONST unsigned char default_dModP[64] = { +0x8e,0x80,0xbf,0x87,0x11,0x04,0xcf,0x36,0x6c,0x96,0x8d,0xb9,0xfb,0xe6,0xfe,0x0c, +0xce,0x74,0x5a,0x56,0x67,0x8c,0x5f,0x66,0x54,0x56,0x04,0x03,0x24,0x9f,0xec,0x4c, +0xaa,0xe1,0x71,0x11,0x7e,0xe9,0x3a,0x2b,0x87,0x07,0x5c,0xe6,0x5a,0xa8,0x71,0xa2, +0xad,0xf3,0x17,0x4e,0x7e,0xa6,0xef,0x5a,0xce,0xcc,0x84,0xd7,0x21,0x91,0x29,0xf1 +}; + +static CONST unsigned char default_dModQ[64] = { +0x87,0x60,0x1d,0x02,0xdb,0x82,0x1e,0x8b,0x07,0x48,0xe8,0x5c,0x59,0xeb,0x62,0xa4, +0x15,0xff,0x95,0x12,0x82,0xfd,0xd9,0x8d,0xf2,0x6c,0x3a,0x2f,0x9b,0x30,0x51,0x6a, +0xdb,0x80,0x6f,0xa1,0xef,0xee,0x8c,0x69,0x63,0xd1,0xa4,0xdb,0x9c,0x8f,0x80,0xe5, +0xfb,0x3f,0x33,0x8e,0x3d,0x3c,0x6b,0xa1,0x6c,0xab,0x20,0x92,0xe0,0xd8,0xcd,0xa1 +}; + +static CONST unsigned char default_qInvModP[64] = { +0xce,0xcf,0x5a,0xad,0xc4,0x8c,0x44,0x91,0x3a,0xbc,0x7b,0xf8,0x80,0xf8,0x53,0xf5, +0x12,0x84,0x8c,0x9c,0x6b,0x33,0x93,0x0d,0xa1,0x11,0xea,0xfa,0x4a,0xc1,0xeb,0x48, +0xdc,0x44,0x86,0x93,0x1b,0x98,0xc7,0x82,0x22,0x68,0x30,0x44,0xd7,0x62,0x1b,0x90, +0x54,0x07,0x4b,0x66,0xa7,0xc5,0x75,0x5a,0x72,0x77,0x92,0xdd,0x6c,0xf3,0x37,0xab +}; + + +static struct NSSLOWKEYPrivateKeyStr rsaPriv; + +NSSLOWKEYPrivateKey * +getDefaultRSAPrivateKey(void) +{ + if (rsaPriv.keyType != NSSLOWKEYRSAKey) { + + /* leaving arena uninitialized. It isn't used in this test. */ + + rsaPriv.keyType = NSSLOWKEYRSAKey; + + /* leaving arena uninitialized. It isn't used. */ + /* leaving version uninitialized. It isn't used. */ + + rsaPriv.u.rsa.modulus.data = default_n; + rsaPriv.u.rsa.modulus.len = sizeof default_n; + rsaPriv.u.rsa.publicExponent.data = default_e; + rsaPriv.u.rsa.publicExponent.len = sizeof default_e; + rsaPriv.u.rsa.privateExponent.data = default_d; + rsaPriv.u.rsa.privateExponent.len = sizeof default_d; + rsaPriv.u.rsa.prime1.data = default_p; + rsaPriv.u.rsa.prime1.len = sizeof default_p; + rsaPriv.u.rsa.prime2.data = default_q; + rsaPriv.u.rsa.prime2.len = sizeof default_q; + rsaPriv.u.rsa.exponent1.data = default_dModP; + rsaPriv.u.rsa.exponent1.len = sizeof default_dModP; + rsaPriv.u.rsa.exponent2.data = default_dModQ; + rsaPriv.u.rsa.exponent2.len = sizeof default_dModQ; + rsaPriv.u.rsa.coefficient.data = default_qInvModP; + rsaPriv.u.rsa.coefficient.len = sizeof default_qInvModP; + } + return &rsaPriv; +} + +static struct NSSLOWKEYPublicKeyStr rsaPub; + +NSSLOWKEYPublicKey * +getDefaultRSAPublicKey(void) +{ + if (rsaPub.keyType != NSSLOWKEYRSAKey) { + + rsaPub.keyType = NSSLOWKEYRSAKey; + + rsaPub.u.rsa.modulus.data = default_n; + rsaPub.u.rsa.modulus.len = sizeof default_n; + + rsaPub.u.rsa.publicExponent.data = default_e; + rsaPub.u.rsa.publicExponent.len = sizeof default_e; + } + return &rsaPub; +} + +/* modPop = 536, privPop = 531, ex1Pop = 261, ex2Pop = 257 + * After 46 tries, found this key: + * Version: 0 (0x0) + * Modulus: + * c2:ae:96:89:af:ce:d0:7b:3b:35:fd:0f:b1:f4:7a:d1:3c:7d:b5: + * 86:f2:68:36:c9:97:e6:82:94:86:aa:05:39:ec:11:51:cc:5c:a1: + * 59:ba:29:18:f3:28:f1:9d:e3:ae:96:5d:6d:87:73:f6:f6:1f:d0: + * 2d:fb:2f:7a:13:7f:c8:0c:7a:e9:85:fb:ce:74:86:f8:ef:2f:85: + * 37:73:0f:62:4e:93:17:b7:7e:84:9a:94:11:05:ca:0d:31:4b:2a: + * c8:df:fe:e9:0c:13:c7:f2:ad:19:64:28:3c:b5:6a:c8:4b:79:ea: + * 7c:ce:75:92:45:3e:a3:9d:64:6f:04:69:19:17 + * Public Exponent: 65537 (0x10001) + * Private Exponent: + * 13:cb:bc:f2:f3:35:8c:6d:7b:6f:d9:f3:a6:9c:bd:80:59:2e:4f: + * 2f:11:a7:17:2b:18:8f:0f:e8:1a:69:5f:6e:ac:5a:76:7e:d9:4c: + * 6e:db:47:22:8a:57:37:7a:5e:94:7a:25:b5:e5:78:1d:3c:99:af: + * 89:7d:69:2e:78:9d:1d:84:c8:c1:d7:1a:b2:6d:2d:8a:d9:ab:6b: + * ce:ae:b0:a0:58:55:ad:5c:40:8a:d6:96:08:8a:e8:63:e6:3d:6c: + * 20:49:c7:af:0f:25:73:d3:69:43:3b:f2:32:f8:3d:5e:ee:7a:ca: + * d6:94:55:e5:bd:25:34:8d:63:40:b5:8a:c3:01 + * Prime 1: + * f6:3c:3f:56:58:4f:b3:82:0c:f0:5b:42:36:1c:93:de:9b:32:01: + * b1:48:f8:00:57:9b:c1:be:66:c2:bb:ea:7c:75:29:2c:22:aa:7c: + * af:bd:0d:3f:b0:64:97:f0:88:25:cb:8d:c7:19:0a:75:44:a4:5a: + * c3:b5:b9:85:ea:27:a7 + * Prime 2: + * ca:66:fa:18:6a:46:36:1c:46:fe:47:e9:7e:52:83:8a:bb:72:13: + * cc:83:56:3d:64:22:dd:fa:7c:61:99:ea:a4:b3:0e:8f:79:10:ab: + * ba:4a:73:d1:48:40:34:34:d3:d2:54:92:be:f5:c8:c4:60:5f:d3: + * f7:ce:be:60:3e:b1:11 + * Exponent 1: + * 8e:80:bf:87:11:04:cf:36:6c:96:8d:b9:fb:e6:fe:0c:ce:74:5a: + * 56:67:8c:5f:66:54:56:04:03:24:9f:ec:4c:aa:e1:71:11:7e:e9: + * 3a:2b:87:07:5c:e6:5a:a8:71:a2:ad:f3:17:4e:7e:a6:ef:5a:ce: + * cc:84:d7:21:91:29:f1 + * Exponent 2: + * 87:60:1d:02:db:82:1e:8b:07:48:e8:5c:59:eb:62:a4:15:ff:95: + * 12:82:fd:d9:8d:f2:6c:3a:2f:9b:30:51:6a:db:80:6f:a1:ef:ee: + * 8c:69:63:d1:a4:db:9c:8f:80:e5:fb:3f:33:8e:3d:3c:6b:a1:6c: + * ab:20:92:e0:d8:cd:a1 + * Coefficient: + * ce:cf:5a:ad:c4:8c:44:91:3a:bc:7b:f8:80:f8:53:f5:12:84:8c: + * 9c:6b:33:93:0d:a1:11:ea:fa:4a:c1:eb:48:dc:44:86:93:1b:98: + * c7:82:22:68:30:44:d7:62:1b:90:54:07:4b:66:a7:c5:75:5a:72: + * 77:92:dd:6c:f3:37:ab + */ + diff --git a/security/nss/cmd/rsaperf/manifest.mn b/security/nss/cmd/rsaperf/manifest.mn new file mode 100644 index 000000000..802a63815 --- /dev/null +++ b/security/nss/cmd/rsaperf/manifest.mn @@ -0,0 +1,52 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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) 1998-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. +# + +DEPTH = ../../.. +CORE_DEPTH = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +INCLUDES += -I$(CORE_DEPTH)/nss/lib/softoken + +# This next line is used by .mk files +# and gets translated into $LINCS in manifest.mnw +REQUIRES = dbm seccmd + +# DIRS = + +CSRCS = rsaperf.c defkey.c + +PROGRAM = rsaperf + +USE_STATIC_LIBS = 1 diff --git a/security/nss/cmd/rsaperf/rsaperf.c b/security/nss/cmd/rsaperf/rsaperf.c new file mode 100644 index 000000000..36927e718 --- /dev/null +++ b/security/nss/cmd/rsaperf/rsaperf.c @@ -0,0 +1,402 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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) 1998-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" +#include "cert.h" +#include "secutil.h" +#include "nspr.h" +#include "nss.h" +#include "blapi.h" +#include "plgetopt.h" +#include "lowkeyi.h" + + +#define MAX_RSA_MODULUS_BYTES (1024/8) +#define DEFAULT_ITERS 10 + +extern NSSLOWKEYPrivateKey * getDefaultRSAPrivateKey(void); +extern NSSLOWKEYPublicKey * getDefaultRSAPublicKey(void); + +typedef struct TimingContextStr TimingContext; + +struct TimingContextStr { + int64 start; + int64 end; + int64 interval; + + long days; + int hours; + int minutes; + int seconds; + int millisecs; +}; + +TimingContext *CreateTimingContext(void) { + return PR_Malloc(sizeof(TimingContext)); +} + +void DestroyTimingContext(TimingContext *ctx) { + PR_Free(ctx); +} + +void TimingBegin(TimingContext *ctx) { + ctx->start = PR_Now(); +} + +static void timingUpdate(TimingContext *ctx) { + int64 tmp, remaining; + int64 L1000,L60,L24; + + LL_I2L(L1000,1000); + LL_I2L(L60,60); + LL_I2L(L24,24); + + LL_DIV(remaining, ctx->interval, L1000); + LL_MOD(tmp, remaining, L1000); + LL_L2I(ctx->millisecs, tmp); + LL_DIV(remaining, remaining, L1000); + LL_MOD(tmp, remaining, L60); + LL_L2I(ctx->seconds, tmp); + LL_DIV(remaining, remaining, L60); + LL_MOD(tmp, remaining, L60); + LL_L2I(ctx->minutes, tmp); + LL_DIV(remaining, remaining, L60); + LL_MOD(tmp, remaining, L24); + LL_L2I(ctx->hours, tmp); + LL_DIV(remaining, remaining, L24); + LL_L2I(ctx->days, remaining); +} + +void TimingEnd(TimingContext *ctx) { + ctx->end = PR_Now(); + LL_SUB(ctx->interval, ctx->end, ctx->start); + PORT_Assert(LL_GE_ZERO(ctx->interval)); + timingUpdate(ctx); +} + +void TimingDivide(TimingContext *ctx, int divisor) { + int64 tmp; + + LL_I2L(tmp, divisor); + LL_DIV(ctx->interval, ctx->interval, tmp); + + timingUpdate(ctx); +} + +char *TimingGenerateString(TimingContext *ctx) { + char *buf = NULL; + + if (ctx->days != 0) { + buf = PR_sprintf_append(buf, "%d days", ctx->days); + } + if (ctx->hours != 0) { + if (buf != NULL) buf = PR_sprintf_append(buf, ", "); + buf = PR_sprintf_append(buf, "%d hours", ctx->hours); + } + if (ctx->minutes != 0) { + if (buf != NULL) buf = PR_sprintf_append(buf, ", "); + buf = PR_sprintf_append(buf, "%d minutes", ctx->minutes); + } + if (buf != NULL) buf = PR_sprintf_append(buf, ", and "); + if (!buf && ctx->seconds == 0) { + int interval; + LL_L2I(interval, ctx->interval); + if (ctx->millisecs < 100) + buf = PR_sprintf_append(buf, "%d microseconds", interval); + else + buf = PR_sprintf_append(buf, "%d milliseconds", ctx->millisecs); + } else if (ctx->millisecs == 0) { + buf = PR_sprintf_append(buf, "%d seconds", ctx->seconds); + } else { + buf = PR_sprintf_append(buf, "%d.%03d seconds", + ctx->seconds, ctx->millisecs); + } + return buf; +} + +void +Usage(char *progName) +{ + fprintf(stderr, "Usage: %s [-d certdir] [-i iterations] [-s | -e]" + " -n nickname\n", + progName); + fprintf(stderr, "%-20s Cert database directory (default is ~/.netscape)\n", + "-d certdir"); + fprintf(stderr, "%-20s How many operations to perform\n", "-i iterations"); + fprintf(stderr, "%-20s Perform signing (private key) operations\n", "-s"); + fprintf(stderr, "%-20s Perform encryption (public key) operations\n", "-e"); + fprintf(stderr, "%-20s Nickname of certificate or key\n", "-n nickname"); + exit(-1); +} + +void +printCount(int iterations) +{ + +} + + +static void +dumpBytes( unsigned char * b, int l) +{ + int i; + if (l <= 0) + return; + for (i = 0; i < l; ++i) { + if (i % 16 == 0) + printf("\t"); + printf(" %02x", b[i]); + if (i % 16 == 15) + printf("\n"); + } + if ((i % 16) != 0) + printf("\n"); +} + +static void +dumpItem( SECItem * item, const char * description) +{ + if (item->len & 1 && item->data[0] == 0) { + printf("%s: (%d bytes)\n", description, item->len - 1); + dumpBytes(item->data + 1, item->len - 1); + } else { + printf("%s: (%d bytes)\n", description, item->len); + dumpBytes(item->data, item->len); + } +} + +void +printPrivKey(NSSLOWKEYPrivateKey * privKey) +{ + RSAPrivateKey *rsa = &privKey->u.rsa; + + dumpItem( &rsa->modulus, "n"); + dumpItem( &rsa->publicExponent, "e"); + dumpItem( &rsa->privateExponent, "d"); + dumpItem( &rsa->prime1, "P"); + dumpItem( &rsa->prime2, "Q"); + dumpItem( &rsa->exponent1, "d % (P-1)"); + dumpItem( &rsa->exponent2, "d % (Q-1)"); + dumpItem( &rsa->coefficient, "(Q ** -1) % P"); + puts(""); +} + +void +printFnCounts(long doPrint) +{ + +} + +typedef SECStatus (* RSAOp)(void * key, + unsigned char * output, + unsigned char * input); + + +int +main(int argc, char **argv) +{ + TimingContext * timeCtx; + SECKEYPublicKey * pubHighKey; + NSSLOWKEYPrivateKey * privKey; + NSSLOWKEYPublicKey * pubKey; + CERTCertificate * cert; + char * progName; + char * secDir = NULL; + char * nickname = NULL; + RSAOp fn; + void * rsaKey; + PLOptState * optstate; + PLOptStatus optstatus; + long iters = DEFAULT_ITERS; + int i; + PRBool doPriv = PR_FALSE; + PRBool doPub = PR_FALSE; + int rv; + CERTCertDBHandle * certdb; + unsigned char buf[1024]; + unsigned char buf2[1024]; + + progName = strrchr(argv[0], '/'); + if (!progName) + progName = strrchr(argv[0], '\\'); + progName = progName ? progName+1 : argv[0]; + + optstate = PL_CreateOptState(argc, argv, "d:i:sen:"); + while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case '?': + Usage(progName); + break; + case 'd': + secDir = PORT_Strdup(optstate->value); + break; + case 'i': + iters = atol(optstate->value); + break; + case 's': + doPriv = PR_TRUE; + break; + case 'e': + doPub = PR_TRUE; + break; + case 'n': + nickname = PORT_Strdup(optstate->value); + break; + } + } + if (optstatus == PL_OPT_BAD) + Usage(progName); + + if ((doPriv && doPub) || (nickname == NULL)) Usage(progName); + + if (!doPriv && !doPub) doPriv = PR_TRUE; + + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + + secDir = SECU_ConfigDirectory(secDir); + if (strcmp(nickname, "none")) { + rv = NSS_Init(secDir); + if (rv != SECSuccess) { + fprintf(stderr, "NSS_Init failed.\n"); + exit(1); + } + certdb = CERT_GetDefaultCertDB(); + } else { + rv = NSS_NoDB_Init(secDir); + if (rv != SECSuccess) { + fprintf(stderr, "NSS_NoDB_Init failed.\n"); + exit(1); + } + } +#if defined(SECU_GetPassword) + if (doPub) { + if (!strcmp(nickname, "none")) { + pubKey = getDefaultRSAPublicKey(); + } else { + cert = CERT_FindCertByNickname(certdb, nickname); + if (cert == NULL) { + fprintf(stderr, + "Can't find certificate by name \"%s\"\n", nickname); + exit(1); + } + pubHighKey = CERT_ExtractPublicKey(cert); + pubKey = SECU_ConvHighToLow(pubHighKey); + } + if (pubKey == NULL) { + fprintf(stderr, "Can't extract public key from certificate"); + exit(1); + } + fn = (RSAOp)RSA_PublicKeyOp; + rsaKey = (void *)(&pubKey->u.rsa); + } + + if (doPriv) { + + if (!strcmp(nickname, "none")) { + privKey = getDefaultRSAPrivateKey(); + } else { + cert = CERT_FindCertByNickname(certdb, nickname); + if (cert == NULL) { + fprintf(stderr, + "Can't find certificate by name \"%s\"\n", nickname); + exit(1); + } + + privKey = SECKEY_FindKeyByCert(keydb, cert, SECU_GetPassword, NULL); + } + if (privKey == NULL) { + fprintf(stderr, + "Can't find private key by name \"%s\"\n", nickname); + exit(1); + } + + fn = (RSAOp)RSA_PrivateKeyOp; + rsaKey = (void *)(&privKey->u.rsa); + } +#else + if (doPub) { + pubKey = getDefaultRSAPublicKey(); + fn = (RSAOp)RSA_PublicKeyOp; + rsaKey = (void *)(&pubKey->u.rsa); + } + if (doPriv) { + privKey = getDefaultRSAPrivateKey(); + fn = (RSAOp)RSA_PrivateKeyOp; + rsaKey = (void *)(&privKey->u.rsa); + } +#endif + + memset(buf, 1, sizeof buf); + rv = fn(rsaKey, buf2, buf); + if (rv != SECSuccess) { + PRErrorCode errNum; + const char * errStr = NULL; + + errNum = PR_GetError(); + if (errNum) + errStr = SECU_Strerror(errNum); + else + errNum = rv; + if (!errStr) + errStr = "(null)"; + fprintf(stderr, "Error in RSA operation: %d : %s\n", errNum, errStr); + exit(1); + } + +/* printf("START\n"); */ + + timeCtx = CreateTimingContext(); + TimingBegin(timeCtx); + i = iters; + while (i--) { + rv = fn(rsaKey, buf2, buf); + if (rv != SECSuccess) { + PRErrorCode errNum = PR_GetError(); + const char * errStr = SECU_Strerror(errNum); + fprintf(stderr, "Error in RSA operation: %d : %s\n", + errNum, errStr); + exit(1); + } + } + TimingEnd(timeCtx); + printf("%ld iterations in %s\n", + iters, TimingGenerateString(timeCtx)); + TimingDivide(timeCtx, iters); + printf("one operation every %s\n", TimingGenerateString(timeCtx)); + + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + + return 0; +} diff --git a/security/nss/cmd/samples/cert b/security/nss/cmd/samples/cert new file mode 100644 index 000000000..3f8ec48df --- /dev/null +++ b/security/nss/cmd/samples/cert @@ -0,0 +1,15 @@ +-----BEGIN CERTIFICATE----- +MIIB7TCCAVYCAgMaMA0GCSqGSIb3DQEBBAUAMEcxCzAJBgNVBAYTAlVTMRAwDgYD +VQQLEwdUZXN0IENBMSYwJAYDVQQKEx1OZXRzY2FwZSBDb21tdW5pY2F0aW9ucyBD +b3JwLjAeFw05NTEyMDgwMjQwMjdaFw05NjAzMDcwMjQwMjdaMDgxFjAUBgNVBAMT +DURhdmlkIGthcmx0b24xETAPBgNVBAoTCE5ldHNjYXBlMQswCQYDVQQGEwJVUzCB +nTANBgkqhkiG9w0BAQEFAAOBiwAwgYcCgYEAltV2TH+QxqlgfUFk+UyiYAjByxrC +dCSIa/FwRaPceLvE7ycD9L6AC4JA6k58E6ICsr/Y8TsXT4UmZhhLNc50VgSo8cGQ +lajqIDvntq8M1uCXiVOnXmIAqoB6E8GiqW+9evOkgkumMksSwXiXAhMM7vJt3IU6 +b+FwdF5cRs0u1FUCAQMwDQYJKoZIhvcNAQEEBQADgYEAkFdr3ypcvI2+Xgwfp7+d +YtN7w4UnQ7LR9FKmlnBauTVLmUtichn/O3WMT9cYTtZm5QQVRaE3qrGh0Nr6Ko1E +nIHowd36TN45zkFraWoATfCV/f+P37WaADp20l2ryEY0Jpe4gnoeZ0+/ffoxyajC +LZEJL6Dv2Ed83cebLjYxKsI= + +-----END CERTIFICATE----- + diff --git a/security/nss/cmd/samples/cert0 b/security/nss/cmd/samples/cert0 Binary files differnew file mode 100644 index 000000000..05cdc8553 --- /dev/null +++ b/security/nss/cmd/samples/cert0 diff --git a/security/nss/cmd/samples/cert1 b/security/nss/cmd/samples/cert1 Binary files differnew file mode 100644 index 000000000..38a7d299a --- /dev/null +++ b/security/nss/cmd/samples/cert1 diff --git a/security/nss/cmd/samples/cert2 b/security/nss/cmd/samples/cert2 Binary files differnew file mode 100644 index 000000000..147c3eb9e --- /dev/null +++ b/security/nss/cmd/samples/cert2 diff --git a/security/nss/cmd/samples/pkcs7.ber b/security/nss/cmd/samples/pkcs7.ber Binary files differnew file mode 100644 index 000000000..6e3814c37 --- /dev/null +++ b/security/nss/cmd/samples/pkcs7.ber diff --git a/security/nss/cmd/samples/pkcs7bday.ber b/security/nss/cmd/samples/pkcs7bday.ber Binary files differnew file mode 100644 index 000000000..0ee6cfc13 --- /dev/null +++ b/security/nss/cmd/samples/pkcs7bday.ber diff --git a/security/nss/cmd/samples/pkcs7cnet.ber b/security/nss/cmd/samples/pkcs7cnet.ber Binary files differnew file mode 100644 index 000000000..df2bb2dd1 --- /dev/null +++ b/security/nss/cmd/samples/pkcs7cnet.ber diff --git a/security/nss/cmd/samples/pkcs7news.ber b/security/nss/cmd/samples/pkcs7news.ber Binary files differnew file mode 100644 index 000000000..c46a1786d --- /dev/null +++ b/security/nss/cmd/samples/pkcs7news.ber diff --git a/security/nss/cmd/samples/x509v3.der b/security/nss/cmd/samples/x509v3.der Binary files differnew file mode 100644 index 000000000..1ada57c56 --- /dev/null +++ b/security/nss/cmd/samples/x509v3.der diff --git a/security/nss/cmd/samples/x509v3.txt b/security/nss/cmd/samples/x509v3.txt new file mode 100644 index 000000000..dde307697 --- /dev/null +++ b/security/nss/cmd/samples/x509v3.txt @@ -0,0 +1,10 @@ +MIIByzCCAXWgAwIBAgIBADANBgkqhkiG9w0BAQQFADBLMQswCQYDVQQGEwJVUzEW +MBQGA1UEChMNVmVyaVNpZ24gSW5jLjEUMBIGA1UECxMLRW5naW5lZXJpbmcxDjAM +BgNVBAMTBUphc29uMB4XDTk1MDgwODA3MDAwMFoXDTk2MDgwNzA3MDAwMFowSzEL +MAkGA1UEBhMCVVMxFjAUBgNVBAoTDVZlcmlTaWduIEluYy4xFDASBgNVBAsTC0Vu +Z2luZWVyaW5nMQ4wDAYDVQQDEwVKYXNvbjBcMA0GCSqGSIb3DQEBAQUAA0sAMEgC +QQCvpXRU9t3NPFXvxJz2vuxX4zI55AA+xY1PsAEadhwWEMF2EnpG8woF4EGTwLdx +xrw3Eirzu5RAAhqegCN1aPVBAgMBAAGjRDBCMBQGA2FiYwEB/wQKZXh0ZW5zaW9u +MTAUBgNkZWYBAf8ECmV4dGVuc2lvbjIwFAYDZ2hpAQH/BApleHRlbnNpb24zMA0G +CSqGSIb3DQEBBAUAA0EAawLNWFSYMtywAqkSYJb1gejljqi9QAtLZIM2ui+RCTP2 +jEjW5bp4oU1RX2iBSfU+MdEZx9DpMNjqBLrgOy1Djw== diff --git a/security/nss/cmd/sdrtest/Makefile b/security/nss/cmd/sdrtest/Makefile new file mode 100644 index 000000000..490f738e5 --- /dev/null +++ b/security/nss/cmd/sdrtest/Makefile @@ -0,0 +1,73 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk diff --git a/security/nss/cmd/sdrtest/manifest.mn b/security/nss/cmd/sdrtest/manifest.mn new file mode 100644 index 000000000..a8a08fed0 --- /dev/null +++ b/security/nss/cmd/sdrtest/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +CSRCS = \ + sdrtest.c \ + $(NULL) + +# headers for the MODULE (defined above) are implicitly required. +REQUIRES = dbm seccmd + +# WINNT uses EXTRA_LIBS as the list of libs to link in. +# Unix uses OS_LIBS for that purpose. +# We can solve this via conditional makefile code, but +# can't do this in manifest.mn because OS_ARCH isn't defined there. +# So, look in the local Makefile for the defines for the list of libs. + +PROGRAM = sdrtest + +#USE_STATIC_LIBS = 1 diff --git a/security/nss/cmd/sdrtest/sdrtest.c b/security/nss/cmd/sdrtest/sdrtest.c new file mode 100644 index 000000000..5bcdd4cde --- /dev/null +++ b/security/nss/cmd/sdrtest/sdrtest.c @@ -0,0 +1,305 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* + * Test program for SDR (Secret Decoder Ring) functions. + * + * $Id$ + */ + +#include "nspr.h" +#include "string.h" +#include "nss.h" +#include "secutil.h" +#include "cert.h" +#include "pk11func.h" + +#include "plgetopt.h" +#include "pk11sdr.h" +#include "secrng.h" + +#define DEFAULT_VALUE "Test" + +static void +synopsis (char *program_name) +{ + PRFileDesc *pr_stderr; + + pr_stderr = PR_STDERR; + PR_fprintf (pr_stderr, "Usage:"); + PR_fprintf (pr_stderr, + "\t%s [-i <input-file>] [-o <output-file>] [-r <text>] [-d <dir>]\n", + program_name); +} + + +static void +short_usage (char *program_name) +{ + PR_fprintf (PR_STDERR, + "Type %s -H for more detailed descriptions\n", + program_name); + synopsis (program_name); +} + + +static void +long_usage (char *program_name) +{ + PRFileDesc *pr_stderr; + + pr_stderr = PR_STDERR; + synopsis (program_name); + PR_fprintf (pr_stderr, "\nSecret Decoder Test:\n"); + PR_fprintf (pr_stderr, + " %-13s Read encrypted data from \"file\"\n", + "-i file"); + PR_fprintf (pr_stderr, + " %-13s Write newly generated encrypted data to \"file\"\n", + "-o file"); + PR_fprintf (pr_stderr, + " %-13s Use \"text\" as the plaintext for encryption and verification\n", + "-t text"); + PR_fprintf (pr_stderr, + " %-13s Find security databases in \"dbdir\"\n", + "-d dbdir"); +} + +int +main (int argc, char **argv) +{ + int retval = 0; /* 0 - test succeeded. -1 - test failed */ + SECStatus rv; + PLOptState *optstate; + char *program_name; + const char *input_file = NULL; /* read encrypted data from here (or create) */ + const char *output_file = NULL; /* write new encrypted data here */ + const char *value = DEFAULT_VALUE; /* Use this for plaintext */ + SECItem data; + SECItem result; + SECItem text; + PRBool verbose = PR_FALSE; + + result.data = 0; + text.data = 0; text.len = 0; + + program_name = PL_strrchr(argv[0], '/'); + program_name = program_name ? (program_name + 1) : argv[0]; + + optstate = PL_CreateOptState (argc, argv, "Hd:i:o:t:v"); + if (optstate == NULL) { + SECU_PrintError (program_name, "PL_CreateOptState failed"); + return -1; + } + + while (PL_GetNextOpt (optstate) == PL_OPT_OK) { + switch (optstate->option) { + case '?': + short_usage (program_name); + return retval; + + case 'H': + long_usage (program_name); + return retval; + + case 'd': + SECU_ConfigDirectory(optstate->value); + break; + + case 'i': + input_file = optstate->value; + break; + + case 'o': + output_file = optstate->value; + break; + + case 't': + value = optstate->value; + break; + + case 'v': + verbose = PR_TRUE; + break; + } + } + + /* + * Initialize the Security libraries. + */ + PK11_SetPasswordFunc(SECU_GetModulePassword); + + if (output_file) { + rv = NSS_InitReadWrite(SECU_ConfigDirectory(NULL)); + } else { + rv = NSS_Init(SECU_ConfigDirectory(NULL)); + } + if (rv != SECSuccess) { + retval = -1; + goto prdone; + } + + /* Convert value into an item */ + data.data = (unsigned char *)value; + data.len = strlen(value); + + /* Get the encrypted result, either from the input file + * or from encrypting the plaintext value + */ + if (input_file) + { + PRFileDesc *file /* = PR_OpenFile(input_file, 0) */; + PRFileInfo info; + PRStatus s; + PRInt32 count; + + if (verbose) printf("Reading data from %s\n", input_file); + + file = PR_Open(input_file, PR_RDONLY, 0); + if (!file) { + if (verbose) printf("Open of file failed\n"); + retval = -1; + goto loser; + } + + s = PR_GetOpenFileInfo(file, &info); + if (s != PR_SUCCESS) { + if (verbose) printf("File info operation failed\n"); + retval = -1; + goto file_loser; + } + + result.len = info.size; + result.data = (unsigned char *)malloc(result.len); + if (!result.data) { + if (verbose) printf("Allocation of buffer failed\n"); + retval = -1; + goto file_loser; + } + + count = PR_Read(file, result.data, result.len); + if (count != result.len) { + if (verbose) printf("Read failed\n"); + retval = -1; + goto file_loser; + } + +file_loser: + PR_Close(file); + if (retval != 0) goto loser; + } + else + { + SECItem keyid = { 0, 0, 0 }; + PK11SlotInfo *slot = NULL; + + /* sigh, initialize the key database */ + slot = PK11_GetInternalKeySlot(); + if (slot && PK11_NeedUserInit(slot)) { + rv = SECU_ChangePW(slot, "", 0); + if (rv != SECSuccess) { + SECU_PrintError(program_name, "Failed to initialize slot \"%s\"", + PK11_GetSlotName(slot)); + return SECFailure; + } + } + if (slot) { + PK11_FreeSlot(slot); + } + + rv = PK11SDR_Encrypt(&keyid, &data, &result, 0); + if (rv != SECSuccess) { + if (verbose) printf("Encrypt operation failed\n"); + retval = -1; + goto loser; + } + + if (verbose) printf("Encrypted result is %d bytes long\n", result.len); + + /* -v printf("Result is %.*s\n", text.len, text.data); */ + if (output_file) + { + PRFileDesc *file; + PRInt32 count; + + if (verbose) printf("Writing result to %s\n", output_file); + + /* Write to file */ + file = PR_Open(output_file, PR_CREATE_FILE|PR_WRONLY, 0666); + if (!file) { + if (verbose) printf("Open of output file failed\n"); + retval = -1; + goto loser; + } + + count = PR_Write(file, result.data, result.len); + + PR_Close(file); + + if (count != result.len) { + if (verbose) printf("Write failed\n"); + retval = -1; + goto loser; + } + } + } + + /* Decrypt the value */ + rv = PK11SDR_Decrypt(&result, &text, 0); + if (rv != SECSuccess) { + if (verbose) printf("Decrypt operation failed\n"); + retval = -1; + goto loser; + } + + if (verbose) printf("Decrypted result is %.*s\n", text.len, text.data); + + /* Compare to required value */ + if (text.len != data.len || memcmp(data.data, text.data, text.len) != 0) + { + if (verbose) printf("Comparison failed\n"); + retval = -1; + goto loser; + } + +loser: + if (text.data) free(text.data); + if (result.data) free(result.data); + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + +prdone: + PR_Cleanup (); + return retval; +} diff --git a/security/nss/cmd/selfserv/Makefile b/security/nss/cmd/selfserv/Makefile new file mode 100644 index 000000000..f2a407990 --- /dev/null +++ b/security/nss/cmd/selfserv/Makefile @@ -0,0 +1,74 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/selfserv/makefile.win b/security/nss/cmd/selfserv/makefile.win new file mode 100644 index 000000000..8fda0b906 --- /dev/null +++ b/security/nss/cmd/selfserv/makefile.win @@ -0,0 +1,136 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +VERBOSE = 1 +include <manifest.mn> + +#cannot define PROGRAM in manifest compatibly with NT and UNIX +PROGRAM = selfserv +PROGRAM = ./$(OBJDIR)/$(PROGRAM).exe +include <$(DEPTH)\config\config.mak> + +# let manifest generate C_OBJS, it will prepend ./$(OBJDIR)/ +# rules.mak will append C_OBJS onto OBJS. +# OBJS = $(CSRCS:.c=.obj) + +# include files are looked for in $LINCS and $INCS. +# $LINCS is in manifest.mnw, computed from REQUIRES= +INCS = $(INCS) \ + -I$(DEPTH)/security/lib/cert \ + -I../include \ + $(NULL) + +IGNORE_ME = \ + -I$(DEPTH)/security/lib/key \ + -I$(DEPTH)/security/lib/util \ + $(NULL) + + +WINFE = $(DEPTH)/cmd/winfe/mkfiles$(MOZ_BITS)/x86Dbg + +# these files are the content of libdbm +DBM_LIB = \ + $(WINFE)/DB.obj \ + $(WINFE)/HASH.obj \ + $(WINFE)/H_BIGKEY.obj \ + $(WINFE)/H_PAGE.obj \ + $(WINFE)/H_LOG2.obj \ + $(WINFE)/H_FUNC.obj \ + $(WINFE)/HASH_BUF.obj \ + $(NULL) + +MOZ_LIBS = \ + $(WINFE)/ALLXPSTR.obj \ + $(WINFE)/XP_ERROR.obj \ + $(WINFE)/XPASSERT.obj \ + $(WINFE)/XP_REG.obj \ + $(WINFE)/XP_TRACE.obj \ + $(DBM_LIB) \ + $(WINFE)/XP_STR.obj \ + $(WINFE)/MKTEMP.obj \ + $(NULL) + +IGNORE_ME2 = \ + $(WINFE)/feutil.obj \ + $(WINFE)/fenet.obj \ + $(WINFE)/fegui.obj \ + $(NULL) + +SEC_LIBS = \ + $(DIST)/lib/cert$(MOZ_BITS).lib \ + $(DIST)/lib/crypto$(MOZ_BITS).lib \ + $(DIST)/lib/hash$(MOZ_BITS).lib \ + $(DIST)/lib/key$(MOZ_BITS).lib \ + $(DIST)/lib/pkcs7$(MOZ_BITS).lib \ + $(DIST)/lib/secmod$(MOZ_BITS).lib \ + $(DIST)/lib/secutl$(MOZ_BITS).lib \ + $(DIST)/lib/ssl$(MOZ_BITS).lib \ + $(NULL) + +LLFLAGS = $(LLFLAGS) \ + $(SEC_LIBS) \ + ../lib/$(OBJDIR)/sectool$(MOZ_BITS).lib \ + $(MOZ_LIBS) \ + $(DEPTH)/nspr/src/$(OBJDIR)/getopt.obj \ + $(LIBNSPR) \ + $(NULL) + + +include <$(DEPTH)\config\rules.mak> + +INSTALL = $(MAKE_INSTALL) + +objs: $(OBJS) + +$(PROGRAM):: + $(INSTALL) $(DIST)/bin/pr3240.dll ./$(OBJDIR) + +programs: $(PROGRAM) + +install:: $(TARGETS) + $(INSTALL) $(TARGETS) $(DIST)/bin + + +symbols: + @echo "CSRCS = $(CSRCS)" + @echo "INCS = $(INCS)" + @echo "OBJS = $(OBJS)" + @echo "LIBRARY = $(LIBRARY)" + @echo "PROGRAM = $(PROGRAM)" + @echo "TARGETS = $(TARGETS)" + @echo "DIST = $(DIST)" + @echo "VERSION_NUMBER = $(VERSION_NUMBER)" + @echo "WINFE = $(WINFE)" + @echo "DBM_LIB = $(DBM_LIB)" + @echo "INSTALL = $(INSTALL)" + diff --git a/security/nss/cmd/selfserv/manifest.mn b/security/nss/cmd/selfserv/manifest.mn new file mode 100644 index 000000000..e97085201 --- /dev/null +++ b/security/nss/cmd/selfserv/manifest.mn @@ -0,0 +1,48 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +DEFINES += -DNSPR20 + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +CSRCS = selfserv.c + +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = seccmd dbm + +PROGRAM = selfserv + diff --git a/security/nss/cmd/selfserv/selfserv.c b/security/nss/cmd/selfserv/selfserv.c new file mode 100644 index 000000000..41f1efe8b --- /dev/null +++ b/security/nss/cmd/selfserv/selfserv.c @@ -0,0 +1,1752 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the + * terms of 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. + */ + +/* -r flag is interepreted as follows: + * 1 -r means request, not require, on initial handshake. + * 2 -r's mean request and require, on initial handshake. + * 3 -r's mean request, not require, on second handshake. + * 4 -r's mean request and require, on second handshake. + */ +#include <stdio.h> +#include <string.h> + +#include "secutil.h" + +#if defined(XP_UNIX) +#include <unistd.h> +#endif + +#if defined(_WINDOWS) +#include <process.h> /* for getpid() */ +#endif + +#ifdef XP_OS2_VACPP +#include <Process.h> /* for getpid() */ +#endif + +#include <stdlib.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> + +#include "nspr.h" +#include "prio.h" +#include "prerror.h" +#include "prnetdb.h" +#include "prclist.h" +#include "plgetopt.h" +#include "pk11func.h" +#include "secitem.h" +#include "nss.h" +#include "ssl.h" +#include "sslproto.h" + +#ifndef PORT_Sprintf +#define PORT_Sprintf sprintf +#endif + +#ifndef PORT_Strstr +#define PORT_Strstr strstr +#endif + +#ifndef PORT_Malloc +#define PORT_Malloc PR_Malloc +#endif + +#define NUM_SID_CACHE_ENTRIES 1024 + +static int handle_connection( PRFileDesc *, PRFileDesc *, int ); + +static const char envVarName[] = { SSL_ENV_VAR_NAME }; +static const char inheritableSockName[] = { "SELFSERV_LISTEN_SOCKET" }; + +static PRBool logStats = PR_FALSE; +static int logPeriod = 30; +static PRUint32 loggerOps = 0; + +const int ssl2CipherSuites[] = { + SSL_EN_RC4_128_WITH_MD5, /* A */ + SSL_EN_RC4_128_EXPORT40_WITH_MD5, /* B */ + SSL_EN_RC2_128_CBC_WITH_MD5, /* C */ + SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */ + SSL_EN_DES_64_CBC_WITH_MD5, /* E */ + SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* F */ +#ifdef NSS_ENABLE_ECC + /* NOTE: Since no new SSL2 ciphersuites are being + * invented, and we've run out of lowercase letters + * for SSL3 ciphers, we use letters G and beyond + * for new SSL3 ciphers. A -1 indicates the cipher + * is not currently implemented. + */ + -1, /* TLS_ECDH_ECDSA_WITH_NULL_SHA, * G */ + -1, /* TLS_ECDH_ECDSA_WITH_RC4_128_SHA, * H */ + -1, /* TLS_ECDH_ECDSA_WITH_DES_CBC_SHA, * I */ + -1, /* TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, * J */ + -1, /* TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, * K */ + -1, /* TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, * L */ + -1, /* TLS_ECDH_RSA_WITH_NULL_SHA, * M */ + -1, /* TLS_ECDH_RSA_WITH_RC4_128_SHA, * N */ + -1, /* TLS_ECDH_RSA_WITH_DES_CBC_SHA, * O */ + -1, /* TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, * P */ + -1, /* TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, * Q */ + -1, /* TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, * R */ + -1, /* TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, * S */ + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* T */ +#endif /* NSS_ENABLE_ECC */ + 0 +}; + +const int ssl3CipherSuites[] = { + SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, /* a */ + SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, /* b */ + SSL_RSA_WITH_RC4_128_MD5, /* c */ + SSL_RSA_WITH_3DES_EDE_CBC_SHA, /* d */ + SSL_RSA_WITH_DES_CBC_SHA, /* e */ + SSL_RSA_EXPORT_WITH_RC4_40_MD5, /* f */ + SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* g */ + SSL_FORTEZZA_DMS_WITH_NULL_SHA, /* h */ + SSL_RSA_WITH_NULL_MD5, /* i */ + SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, /* j */ + SSL_RSA_FIPS_WITH_DES_CBC_SHA, /* k */ + TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, /* l */ + TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, /* m */ + SSL_RSA_WITH_RC4_128_SHA, /* n */ + -1, /* TLS_DHE_DSS_WITH_RC4_128_SHA, * o */ + -1, /* SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, * p */ + -1, /* SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, * q */ + -1, /* SSL_DHE_RSA_WITH_DES_CBC_SHA, * r */ + -1, /* SSL_DHE_DSS_WITH_DES_CBC_SHA, * s */ + -1, /* TLS_DHE_DSS_WITH_AES_128_CBC_SHA, * t */ + -1, /* TLS_DHE_RSA_WITH_AES_128_CBC_SHA, * u */ + TLS_RSA_WITH_AES_128_CBC_SHA, /* v */ + -1, /* TLS_DHE_DSS_WITH_AES_256_CBC_SHA, * w */ + -1, /* TLS_DHE_RSA_WITH_AES_256_CBC_SHA, * x */ + TLS_RSA_WITH_AES_256_CBC_SHA, /* y */ + SSL_RSA_WITH_NULL_SHA, /* z */ + 0 +}; + +/* data and structures for shutdown */ +static int stopping; + +static PRBool noDelay; +static int requestCert; +static int verbose; +static SECItem bigBuf; + +static PRThread * acceptorThread; + +static PRLogModuleInfo *lm; + +/* Add custom password handler because SECU_GetModulePassword + * makes automation of this program next to impossible. + */ + +char * +ownPasswd(PK11SlotInfo *info, PRBool retry, void *arg) +{ + char * passwd = NULL; + + if ( (!retry) && arg ) { + passwd = PL_strdup((char *)arg); + } + + return passwd; +} + +#define PRINTF if (verbose) printf +#define FPRINTF if (verbose) fprintf +#define FLUSH if (verbose) { fflush(stdout); fflush(stderr); } +#define VLOG(arg) PR_LOG(lm,PR_LOG_DEBUG,arg) + +static void +Usage(const char *progName) +{ + fprintf(stderr, + +"Usage: %s -n rsa_nickname -p port [-3DRTbmrvx] [-w password] [-t threads]\n" +" [-i pid_file] [-c ciphers] [-d dbdir] [-f fortezza_nickname] \n" +" [-L [seconds]] [-M maxProcs] [-l]\n" +"-3 means disable SSL v3\n" +"-D means disable Nagle delays in TCP\n" +"-T means disable TLS\n" +"-R means disable detection of rollback from TLS to SSL3\n" +"-b means try binding to the port and exit\n" +"-m means test the model-socket feature of SSL_ImportFD.\n" +"-r flag is interepreted as follows:\n" +" 1 -r means request, not require, cert on initial handshake.\n" +" 2 -r's mean request and require, cert on initial handshake.\n" +" 3 -r's mean request, not require, cert on second handshake.\n" +" 4 -r's mean request and require, cert on second handshake.\n" +"-v means verbose output\n" +"-x means use export policy.\n" +"-L seconds means log statistics every 'seconds' seconds (default=30).\n" +"-M maxProcs tells how many processes to run in a multi-process server\n" +"-t threads -- specify the number of threads to use for connections.\n" +"-i pid_file file to write the process id of selfserve\n" +"-c ciphers Letter(s) chosen from the following list\n" +"-l means use local threads instead of global threads\n" +"A SSL2 RC4 128 WITH MD5\n" +"B SSL2 RC4 128 EXPORT40 WITH MD5\n" +"C SSL2 RC2 128 CBC WITH MD5\n" +"D SSL2 RC2 128 CBC EXPORT40 WITH MD5\n" +"E SSL2 DES 64 CBC WITH MD5\n" +"F SSL2 DES 192 EDE3 CBC WITH MD5\n" +#ifdef NSS_ENABLE_ECC +"T TLS ECDHE RSA WITH AES 128 CBC SHA\n" +#endif /* NSS_ENABLE_ECC */ +"\n" +"a SSL3 FORTEZZA DMS WITH FORTEZZA CBC SHA\n" +"b SSL3 FORTEZZA DMS WITH RC4 128 SHA\n" +"c SSL3 RSA WITH RC4 128 MD5\n" +"d SSL3 RSA WITH 3DES EDE CBC SHA\n" +"e SSL3 RSA WITH DES CBC SHA\n" +"f SSL3 RSA EXPORT WITH RC4 40 MD5\n" +"g SSL3 RSA EXPORT WITH RC2 CBC 40 MD5\n" +"h SSL3 FORTEZZA DMS WITH NULL SHA\n" +"i SSL3 RSA WITH NULL MD5\n" +"j SSL3 RSA FIPS WITH 3DES EDE CBC SHA\n" +"k SSL3 RSA FIPS WITH DES CBC SHA\n" +"l SSL3 RSA EXPORT WITH DES CBC SHA\t(new)\n" +"m SSL3 RSA EXPORT WITH RC4 56 SHA\t(new)\n" +"n SSL3 RSA WITH RC4 128 SHA\n" +"v SSL3 RSA WITH AES 128 CBC SHA\n" +"y SSL3 RSA WITH AES 256 CBC SHA\n" +"z SSL3 RSA WITH NULL SHA\n" + ,progName); +} + +static const char * +errWarn(char * funcString) +{ + PRErrorCode perr = PR_GetError(); + const char * errString = SECU_Strerror(perr); + + fprintf(stderr, "selfserv: %s returned error %d:\n%s\n", + funcString, perr, errString); + return errString; +} + +static void +errExit(char * funcString) +{ + errWarn(funcString); + exit(3); +} + + +/************************************************************************** +** +** Routines for disabling SSL ciphers. +** +**************************************************************************/ + +void +disableAllSSLCiphers(void) +{ + const PRUint16 *cipherSuites = SSL_ImplementedCiphers; + int i = SSL_NumImplementedCiphers; + SECStatus rv; + + /* disable all the SSL3 cipher suites */ + while (--i >= 0) { + PRUint16 suite = cipherSuites[i]; + rv = SSL_CipherPrefSetDefault(suite, PR_FALSE); + if (rv != SECSuccess) { + printf("SSL_CipherPrefSetDefault didn't like value 0x%04x (i = %d)\n", + suite, i); + errWarn("SSL_CipherPrefSetDefault"); + exit(2); + } + } +} + +static SECStatus +mySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, + PRBool isServer) +{ + SECStatus rv; + CERTCertificate * peerCert; + + peerCert = SSL_PeerCertificate(fd); + + PRINTF("selfserv: Subject: %s\nselfserv: Issuer : %s\n", + peerCert->subjectName, peerCert->issuerName); + + rv = SSL_AuthCertificate(arg, fd, checkSig, isServer); + + if (rv == SECSuccess) { + PRINTF("selfserv: -- SSL3: Certificate Validated.\n"); + } else { + int err = PR_GetError(); + FPRINTF(stderr, "selfserv: -- SSL3: Certificate Invalid, err %d.\n%s\n", + err, SECU_Strerror(err)); + } + CERT_DestroyCertificate(peerCert); + FLUSH; + return rv; +} + +void +printSecurityInfo(PRFileDesc *fd) +{ + CERTCertificate * cert = NULL; + SSL3Statistics * ssl3stats = SSL_GetStatistics(); + SECStatus result; + SSLChannelInfo channel; + SSLCipherSuiteInfo suite; + + PRINTF( + "selfserv: %ld cache hits; %ld cache misses, %ld cache not reusable\n", + ssl3stats->hch_sid_cache_hits, ssl3stats->hch_sid_cache_misses, + ssl3stats->hch_sid_cache_not_ok); + + result = SSL_GetChannelInfo(fd, &channel, sizeof channel); + if (result == SECSuccess && + channel.length == sizeof channel && + channel.cipherSuite) { + result = SSL_GetCipherSuiteInfo(channel.cipherSuite, + &suite, sizeof suite); + if (result == SECSuccess) { + FPRINTF(stderr, + "selfserv: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n", + channel.protocolVersion >> 8, channel.protocolVersion & 0xff, + suite.effectiveKeyBits, suite.symCipherName, + suite.macBits, suite.macAlgorithmName); + FPRINTF(stderr, + "selfserv: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n", + channel.authKeyBits, suite.authAlgorithmName, + channel.keaKeyBits, suite.keaTypeName); + } + } + if (requestCert) + cert = SSL_PeerCertificate(fd); + else + cert = SSL_LocalCertificate(fd); + if (cert) { + char * ip = CERT_NameToAscii(&cert->issuer); + char * sp = CERT_NameToAscii(&cert->subject); + if (sp) { + FPRINTF(stderr, "selfserv: subject DN: %s\n", sp); + PR_Free(sp); + } + if (ip) { + FPRINTF(stderr, "selfserv: issuer DN: %s\n", ip); + PR_Free(ip); + } + CERT_DestroyCertificate(cert); + cert = NULL; + } + FLUSH; +} + +static int MakeCertOK; + +static SECStatus +myBadCertHandler( void *arg, PRFileDesc *fd) +{ + int err = PR_GetError(); + if (!MakeCertOK) + fprintf(stderr, + "selfserv: -- SSL: Client Certificate Invalid, err %d.\n%s\n", + err, SECU_Strerror(err)); + return (MakeCertOK ? SECSuccess : SECFailure); +} + +/************************************************************************** +** Begin thread management routines and data. +**************************************************************************/ +#define MIN_THREADS 3 +#define DEFAULT_THREADS 8 +#define MAX_THREADS 128 +#define MAX_PROCS 25 +static int maxThreads = DEFAULT_THREADS; + + +typedef struct jobStr { + PRCList link; + PRFileDesc *tcp_sock; + PRFileDesc *model_sock; + int requestCert; +} JOB; + +static PZLock * qLock; /* this lock protects all data immediately below */ +static PZCondVar * jobQNotEmptyCv; +static PZCondVar * freeListNotEmptyCv; +static PZCondVar * threadCountChangeCv; +static int threadCount; +static PRCList jobQ; +static PRCList freeJobs; +static JOB *jobTable; + +SECStatus +setupJobs(int maxJobs) +{ + int i; + + jobTable = (JOB *)PR_Calloc(maxJobs, sizeof(JOB)); + if (!jobTable) + return SECFailure; + + PR_INIT_CLIST(&jobQ); + PR_INIT_CLIST(&freeJobs); + + for (i = 0; i < maxJobs; ++i) { + JOB * pJob = jobTable + i; + PR_APPEND_LINK(&pJob->link, &freeJobs); + } + return SECSuccess; +} + +typedef int startFn(PRFileDesc *a, PRFileDesc *b, int c); + +typedef enum { rs_idle = 0, rs_running = 1, rs_zombie = 2 } runState; + +typedef struct perThreadStr { + PRFileDesc *a; + PRFileDesc *b; + int c; + int rv; + startFn * startFunc; + PRThread * prThread; + runState state; +} perThread; + +static perThread *threads; + +void +thread_wrapper(void * arg) +{ + perThread * slot = (perThread *)arg; + + slot->rv = (* slot->startFunc)(slot->a, slot->b, slot->c); + + /* notify the thread exit handler. */ + PZ_Lock(qLock); + slot->state = rs_zombie; + --threadCount; + PZ_NotifyAllCondVar(threadCountChangeCv); + PZ_Unlock(qLock); +} + +int +jobLoop(PRFileDesc *a, PRFileDesc *b, int c) +{ + PRCList * myLink = 0; + JOB * myJob; + + PZ_Lock(qLock); + do { + myLink = 0; + while (PR_CLIST_IS_EMPTY(&jobQ) && !stopping) { + PZ_WaitCondVar(jobQNotEmptyCv, PR_INTERVAL_NO_TIMEOUT); + } + if (!PR_CLIST_IS_EMPTY(&jobQ)) { + myLink = PR_LIST_HEAD(&jobQ); + PR_REMOVE_AND_INIT_LINK(myLink); + } + PZ_Unlock(qLock); + myJob = (JOB *)myLink; + /* myJob will be null when stopping is true and jobQ is empty */ + if (!myJob) + break; + handle_connection( myJob->tcp_sock, myJob->model_sock, + myJob->requestCert); + PZ_Lock(qLock); + PR_APPEND_LINK(myLink, &freeJobs); + PZ_NotifyCondVar(freeListNotEmptyCv); + } while (PR_TRUE); + return 0; +} + + +SECStatus +launch_threads( + startFn *startFunc, + PRFileDesc *a, + PRFileDesc *b, + int c, + PRBool local) +{ + int i; + SECStatus rv = SECSuccess; + + /* create the thread management serialization structs */ + qLock = PZ_NewLock(nssILockSelfServ); + jobQNotEmptyCv = PZ_NewCondVar(qLock); + freeListNotEmptyCv = PZ_NewCondVar(qLock); + threadCountChangeCv = PZ_NewCondVar(qLock); + + /* allocate the array of thread slots */ + threads = PR_Calloc(maxThreads, sizeof(perThread)); + if ( NULL == threads ) { + fprintf(stderr, "Oh Drat! Can't allocate the perThread array\n"); + return SECFailure; + } + /* 5 is a little extra, intended to keep the jobQ from underflowing. + ** That is, from going empty while not stopping and clients are still + ** trying to contact us. + */ + rv = setupJobs(maxThreads + 5); + if (rv != SECSuccess) + return rv; + + PZ_Lock(qLock); + for (i = 0; i < maxThreads; ++i) { + perThread * slot = threads + i; + + slot->state = rs_running; + slot->a = a; + slot->b = b; + slot->c = c; + slot->startFunc = startFunc; + slot->prThread = PR_CreateThread(PR_USER_THREAD, + thread_wrapper, slot, PR_PRIORITY_NORMAL, + (PR_TRUE==local)?PR_LOCAL_THREAD:PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (slot->prThread == NULL) { + printf("selfserv: Failed to launch thread!\n"); + slot->state = rs_idle; + rv = SECFailure; + break; + } + + ++threadCount; + } + PZ_Unlock(qLock); + + return rv; +} + +#define DESTROY_CONDVAR(name) if (name) { \ + PZ_DestroyCondVar(name); name = NULL; } +#define DESTROY_LOCK(name) if (name) { \ + PZ_DestroyLock(name); name = NULL; } + + +void +terminateWorkerThreads(void) +{ + VLOG(("selfserv: server_thead: waiting on stopping")); + PZ_Lock(qLock); + PZ_NotifyAllCondVar(jobQNotEmptyCv); + while (threadCount > 0) { + PZ_WaitCondVar(threadCountChangeCv, PR_INTERVAL_NO_TIMEOUT); + } + PZ_Unlock(qLock); + + DESTROY_CONDVAR(jobQNotEmptyCv); + DESTROY_CONDVAR(freeListNotEmptyCv); + DESTROY_CONDVAR(threadCountChangeCv); + + DESTROY_LOCK(qLock); + PR_Free(jobTable); + PR_Free(threads); +} + +static void +logger(void *arg) +{ + PRFloat64 seconds; + PRFloat64 opsPerSec; + PRIntervalTime period; + PRIntervalTime previousTime; + PRIntervalTime latestTime; + PRUint32 previousOps; + PRUint32 ops; + PRIntervalTime logPeriodTicks = PR_SecondsToInterval(logPeriod); + PRFloat64 secondsPerTick = 1.0 / (PRFloat64)PR_TicksPerSecond(); + + previousOps = loggerOps; + previousTime = PR_IntervalNow(); + + for (;;) { + PR_Sleep(logPeriodTicks); + latestTime = PR_IntervalNow(); + ops = loggerOps; + period = latestTime - previousTime; + seconds = (PRFloat64) period*secondsPerTick; + opsPerSec = (ops - previousOps) / seconds; + printf("%.2f ops/second, %d threads\n", opsPerSec, threadCount); + fflush(stdout); + previousOps = ops; + previousTime = latestTime; + } +} + + +/************************************************************************** +** End thread management routines. +**************************************************************************/ + +PRBool useModelSocket = PR_FALSE; +PRBool disableSSL3 = PR_FALSE; +PRBool disableTLS = PR_FALSE; +PRBool disableRollBack = PR_FALSE; + +static const char stopCmd[] = { "GET /stop " }; +static const char getCmd[] = { "GET " }; +static const char EOFmsg[] = { "EOF\r\n\r\n\r\n" }; +static const char outHeader[] = { + "HTTP/1.0 200 OK\r\n" + "Server: Generic Web Server\r\n" + "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n" + "Content-type: text/plain\r\n" + "\r\n" +}; + +#ifdef FULL_DUPLEX_CAPABLE + +struct lockedVarsStr { + PZLock * lock; + int count; + int waiters; + PZCondVar * condVar; +}; + +typedef struct lockedVarsStr lockedVars; + +void +lockedVars_Init( lockedVars * lv) +{ + lv->count = 0; + lv->waiters = 0; + lv->lock = PZ_NewLock(nssILockSelfServ); + lv->condVar = PZ_NewCondVar(lv->lock); +} + +void +lockedVars_Destroy( lockedVars * lv) +{ + PZ_DestroyCondVar(lv->condVar); + lv->condVar = NULL; + + PZ_DestroyLock(lv->lock); + lv->lock = NULL; +} + +void +lockedVars_WaitForDone(lockedVars * lv) +{ + PZ_Lock(lv->lock); + while (lv->count > 0) { + PZ_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT); + } + PZ_Unlock(lv->lock); +} + +int /* returns count */ +lockedVars_AddToCount(lockedVars * lv, int addend) +{ + int rv; + + PZ_Lock(lv->lock); + rv = lv->count += addend; + if (rv <= 0) { + PZ_NotifyCondVar(lv->condVar); + } + PZ_Unlock(lv->lock); + return rv; +} + +int +do_writes( + PRFileDesc * ssl_sock, + PRFileDesc * model_sock, + int requestCert + ) +{ + int sent = 0; + int count = 0; + lockedVars * lv = (lockedVars *)model_sock; + + VLOG(("selfserv: do_writes: starting")); + while (sent < bigBuf.len) { + + count = PR_Write(ssl_sock, bigBuf.data + sent, bigBuf.len - sent); + if (count < 0) { + errWarn("PR_Write bigBuf"); + break; + } + FPRINTF(stderr, "selfserv: PR_Write wrote %d bytes from bigBuf\n", count ); + sent += count; + } + if (count >= 0) { /* last write didn't fail. */ + PR_Shutdown(ssl_sock, PR_SHUTDOWN_SEND); + } + + /* notify the reader that we're done. */ + lockedVars_AddToCount(lv, -1); + FLUSH; + VLOG(("selfserv: do_writes: exiting")); + return (sent < bigBuf.len) ? SECFailure : SECSuccess; +} + +static int +handle_fdx_connection( + PRFileDesc * tcp_sock, + PRFileDesc * model_sock, + int requestCert + ) +{ + PRFileDesc * ssl_sock = NULL; + SECStatus result; + int firstTime = 1; + lockedVars lv; + PRSocketOptionData opt; + char buf[10240]; + + + VLOG(("selfserv: handle_fdx_connection: starting")); + opt.option = PR_SockOpt_Nonblocking; + opt.value.non_blocking = PR_FALSE; + PR_SetSocketOption(tcp_sock, &opt); + + if (useModelSocket && model_sock) { + SECStatus rv; + ssl_sock = SSL_ImportFD(model_sock, tcp_sock); + if (!ssl_sock) { + errWarn("SSL_ImportFD with model"); + goto cleanup; + } + rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 1); + if (rv != SECSuccess) { + errWarn("SSL_ResetHandshake"); + goto cleanup; + } + } else { + ssl_sock = tcp_sock; + } + + lockedVars_Init(&lv); + lockedVars_AddToCount(&lv, 1); + + /* Attempt to launch the writer thread. */ + result = launch_thread(do_writes, ssl_sock, (PRFileDesc *)&lv, + requestCert); + + if (result == SECSuccess) + do { + /* do reads here. */ + int count; + count = PR_Read(ssl_sock, buf, sizeof buf); + if (count < 0) { + errWarn("FDX PR_Read"); + break; + } + FPRINTF(stderr, "selfserv: FDX PR_Read read %d bytes.\n", count ); + if (firstTime) { + firstTime = 0; + printSecurityInfo(ssl_sock); + } + } while (lockedVars_AddToCount(&lv, 0) > 0); + + /* Wait for writer to finish */ + lockedVars_WaitForDone(&lv); + lockedVars_Destroy(&lv); + FLUSH; + +cleanup: + if (ssl_sock) + PR_Close(ssl_sock); + else + PR_Close(tcp_sock); + + VLOG(("selfserv: handle_fdx_connection: exiting")); + return SECSuccess; +} + +#endif + +int +handle_connection( + PRFileDesc *tcp_sock, + PRFileDesc *model_sock, + int requestCert + ) +{ + PRFileDesc * ssl_sock = NULL; + PRFileDesc * local_file_fd = NULL; + char * post; + char * pBuf; /* unused space at end of buf */ + const char * errString; + PRStatus status; + int bufRem; /* unused bytes at end of buf */ + int bufDat; /* characters received in buf */ + int newln = 0; /* # of consecutive newlns */ + int firstTime = 1; + int reqLen; + int rv; + int numIOVs; + PRSocketOptionData opt; + PRIOVec iovs[16]; + char msgBuf[160]; + char buf[10240]; + char fileName[513]; + + pBuf = buf; + bufRem = sizeof buf; + memset(buf, 0, sizeof buf); + + VLOG(("selfserv: handle_connection: starting")); + opt.option = PR_SockOpt_Nonblocking; + opt.value.non_blocking = PR_FALSE; + PR_SetSocketOption(tcp_sock, &opt); + + VLOG(("selfserv: handle_connection: starting\n")); + if (useModelSocket && model_sock) { + SECStatus rv; + ssl_sock = SSL_ImportFD(model_sock, tcp_sock); + if (!ssl_sock) { + errWarn("SSL_ImportFD with model"); + goto cleanup; + } + rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 1); + if (rv != SECSuccess) { + errWarn("SSL_ResetHandshake"); + goto cleanup; + } + } else { + ssl_sock = tcp_sock; + } + + if (noDelay) { + opt.option = PR_SockOpt_NoDelay; + opt.value.no_delay = PR_TRUE; + status = PR_SetSocketOption(ssl_sock, &opt); + if (status != PR_SUCCESS) { + errWarn("PR_SetSocketOption(PR_SockOpt_NoDelay, PR_TRUE)"); + PR_Close(ssl_sock); + return SECFailure; + } + } + + while (1) { + newln = 0; + reqLen = 0; + rv = PR_Read(ssl_sock, pBuf, bufRem); + if (rv == 0 || + (rv < 0 && PR_END_OF_FILE_ERROR == PR_GetError())) { + if (verbose) + errWarn("HDX PR_Read hit EOF"); + break; + } + if (rv < 0) { + errWarn("HDX PR_Read"); + goto cleanup; + } + if (firstTime) { + firstTime = 0; + printSecurityInfo(ssl_sock); + } + + pBuf += rv; + bufRem -= rv; + bufDat = pBuf - buf; + /* Parse the input, starting at the beginning of the buffer. + * Stop when we detect two consecutive \n's (or \r\n's) + * as this signifies the end of the GET or POST portion. + * The posted data follows. + */ + while (reqLen < bufDat && newln < 2) { + int octet = buf[reqLen++]; + if (octet == '\n') { + newln++; + } else if (octet != '\r') { + newln = 0; + } + } + + /* came to the end of the buffer, or second newln + * If we didn't get an empty line (CRLFCRLF) then keep on reading. + */ + if (newln < 2) + continue; + + /* we're at the end of the HTTP request. + * If the request is a POST, then there will be one more + * line of data. + * This parsing is a hack, but ok for SSL test purposes. + */ + post = PORT_Strstr(buf, "POST "); + if (!post || *post != 'P') + break; + + /* It's a post, so look for the next and final CR/LF. */ + /* We should parse content length here, but ... */ + while (reqLen < bufDat && newln < 3) { + int octet = buf[reqLen++]; + if (octet == '\n') { + newln++; + } + } + if (newln == 3) + break; + } /* read loop */ + + bufDat = pBuf - buf; + if (bufDat) do { /* just close if no data */ + /* Have either (a) a complete get, (b) a complete post, (c) EOF */ + if (reqLen > 0 && !strncmp(buf, getCmd, sizeof getCmd - 1)) { + char * fnBegin = buf + 4; + char * fnEnd; + PRFileInfo info; + /* try to open the file named. + * If succesful, then write it to the client. + */ + fnEnd = strpbrk(fnBegin, " \r\n"); + if (fnEnd) { + int fnLen = fnEnd - fnBegin; + if (fnLen < sizeof fileName) { + strncpy(fileName, fnBegin, fnLen); + fileName[fnLen] = 0; /* null terminate */ + status = PR_GetFileInfo(fileName, &info); + if (status == PR_SUCCESS && + info.type == PR_FILE_FILE && + info.size >= 0 ) { + local_file_fd = PR_Open(fileName, PR_RDONLY, 0); + } + } + } + } + /* if user has requested client auth in a subsequent handshake, + * do it here. + */ + if (requestCert > 2) { /* request cert was 3 or 4 */ + CERTCertificate * cert = SSL_PeerCertificate(ssl_sock); + if (cert) { + CERT_DestroyCertificate(cert); + } else { + rv = SSL_OptionSet(ssl_sock, SSL_REQUEST_CERTIFICATE, 1); + if (rv < 0) { + errWarn("second SSL_OptionSet SSL_REQUEST_CERTIFICATE"); + break; + } + rv = SSL_OptionSet(ssl_sock, SSL_REQUIRE_CERTIFICATE, + (requestCert == 4)); + if (rv < 0) { + errWarn("second SSL_OptionSet SSL_REQUIRE_CERTIFICATE"); + break; + } + rv = SSL_ReHandshake(ssl_sock, PR_TRUE); + if (rv != 0) { + errWarn("SSL_ReHandshake"); + break; + } + rv = SSL_ForceHandshake(ssl_sock); + if (rv < 0) { + errWarn("SSL_ForceHandshake"); + break; + } + } + } + + numIOVs = 0; + + iovs[numIOVs].iov_base = (char *)outHeader; + iovs[numIOVs].iov_len = (sizeof(outHeader)) - 1; + numIOVs++; + + if (local_file_fd) { + PRInt32 bytes; + int errLen; + bytes = PR_TransmitFile(ssl_sock, local_file_fd, outHeader, + sizeof outHeader - 1, + PR_TRANSMITFILE_KEEP_OPEN, + PR_INTERVAL_NO_TIMEOUT); + if (bytes >= 0) { + bytes -= sizeof outHeader - 1; + FPRINTF(stderr, + "selfserv: PR_TransmitFile wrote %d bytes from %s\n", + bytes, fileName); + break; + } + errString = errWarn("PR_TransmitFile"); + errLen = PORT_Strlen(errString); + if (errLen > sizeof msgBuf - 1) + errLen = sizeof msgBuf - 1; + PORT_Memcpy(msgBuf, errString, errLen); + msgBuf[errLen] = 0; + + iovs[numIOVs].iov_base = msgBuf; + iovs[numIOVs].iov_len = PORT_Strlen(msgBuf); + numIOVs++; + } else if (reqLen <= 0) { /* hit eof */ + PORT_Sprintf(msgBuf, "Get or Post incomplete after %d bytes.\r\n", + bufDat); + + iovs[numIOVs].iov_base = msgBuf; + iovs[numIOVs].iov_len = PORT_Strlen(msgBuf); + numIOVs++; + } else if (reqLen < bufDat) { + PORT_Sprintf(msgBuf, "Discarded %d characters.\r\n", + bufDat - reqLen); + + iovs[numIOVs].iov_base = msgBuf; + iovs[numIOVs].iov_len = PORT_Strlen(msgBuf); + numIOVs++; + } + + if (reqLen > 0) { + if (verbose > 1) + fwrite(buf, 1, reqLen, stdout); /* display it */ + + iovs[numIOVs].iov_base = buf; + iovs[numIOVs].iov_len = reqLen; + numIOVs++; + +/* printSecurityInfo(ssl_sock); */ + } + + iovs[numIOVs].iov_base = (char *)EOFmsg; + iovs[numIOVs].iov_len = sizeof EOFmsg - 1; + numIOVs++; + + rv = PR_Writev(ssl_sock, iovs, numIOVs, PR_INTERVAL_NO_TIMEOUT); + if (rv < 0) { + errWarn("PR_Writev"); + break; + } + } while (0); + +cleanup: + PR_Close(ssl_sock); + if (local_file_fd) + PR_Close(local_file_fd); + VLOG(("selfserv: handle_connection: exiting\n")); + + /* do a nice shutdown if asked. */ + if (!strncmp(buf, stopCmd, sizeof stopCmd - 1)) { + stopping = 1; + VLOG(("selfserv: handle_connection: stop command")); + PR_Interrupt(acceptorThread); + PZ_TraceFlush(); + } + VLOG(("selfserv: handle_connection: exiting")); + return SECSuccess; /* success */ +} + +SECStatus +do_accepts( + PRFileDesc *listen_sock, + PRFileDesc *model_sock, + int requestCert + ) +{ + PRNetAddr addr; + PRErrorCode perr; + + VLOG(("selfserv: do_accepts: starting")); + PR_SetThreadPriority( PR_GetCurrentThread(), PR_PRIORITY_HIGH); + + acceptorThread = PR_GetCurrentThread(); + while (!stopping) { + PRFileDesc *tcp_sock; + PRCList *myLink; + + FPRINTF(stderr, "\n\n\nselfserv: About to call accept.\n"); + tcp_sock = PR_Accept(listen_sock, &addr, PR_INTERVAL_NO_TIMEOUT); + if (tcp_sock == NULL) { + perr = PR_GetError(); + if ((perr != PR_CONNECT_RESET_ERROR && + perr != PR_PENDING_INTERRUPT_ERROR) || verbose) { + errWarn("PR_Accept"); + } + if (perr == PR_CONNECT_RESET_ERROR) { + FPRINTF(stderr, + "Ignoring PR_CONNECT_RESET_ERROR error - continue\n"); + continue; + } + stopping = 1; + break; + } + + VLOG(("selfserv: do_accept: Got connection\n")); + + if (logStats) { + loggerOps++; + } + + PZ_Lock(qLock); + while (PR_CLIST_IS_EMPTY(&freeJobs) && !stopping) { + PZ_WaitCondVar(freeListNotEmptyCv, PR_INTERVAL_NO_TIMEOUT); + } + if (stopping) { + PZ_Unlock(qLock); + PR_Close(tcp_sock); + break; + } + myLink = PR_LIST_HEAD(&freeJobs); + PR_REMOVE_AND_INIT_LINK(myLink); + /* could release qLock here and reaquire it 7 lines below, but + ** why bother for 4 assignment statements? + */ + { + JOB * myJob = (JOB *)myLink; + myJob->tcp_sock = tcp_sock; + myJob->model_sock = model_sock; + myJob->requestCert = requestCert; + } + + PR_APPEND_LINK(myLink, &jobQ); + PZ_NotifyCondVar(jobQNotEmptyCv); + PZ_Unlock(qLock); + } + + FPRINTF(stderr, "selfserv: Closing listen socket.\n"); + VLOG(("selfserv: do_accepts: exiting")); + PR_Close(listen_sock); + return SECSuccess; +} + +PRFileDesc * +getBoundListenSocket(unsigned short port) +{ + PRFileDesc * listen_sock; + int listenQueueDepth = 5 + (2 * maxThreads); + PRStatus prStatus; + PRNetAddr addr; + PRSocketOptionData opt; + + addr.inet.family = PR_AF_INET; + addr.inet.ip = PR_INADDR_ANY; + addr.inet.port = PR_htons(port); + + listen_sock = PR_NewTCPSocket(); + if (listen_sock == NULL) { + errExit("PR_NewTCPSocket"); + } + + opt.option = PR_SockOpt_Nonblocking; + opt.value.non_blocking = PR_FALSE; + prStatus = PR_SetSocketOption(listen_sock, &opt); + if (prStatus < 0) { + errExit("PR_SetSocketOption(PR_SockOpt_Nonblocking)"); + } + + opt.option=PR_SockOpt_Reuseaddr; + opt.value.reuse_addr = PR_TRUE; + prStatus = PR_SetSocketOption(listen_sock, &opt); + if (prStatus < 0) { + errExit("PR_SetSocketOption(PR_SockOpt_Reuseaddr)"); + } + + prStatus = PR_Bind(listen_sock, &addr); + if (prStatus < 0) { + errExit("PR_Bind"); + } + + prStatus = PR_Listen(listen_sock, listenQueueDepth); + if (prStatus < 0) { + errExit("PR_Listen"); + } + return listen_sock; +} + +void +server_main( + PRFileDesc * listen_sock, + int requestCert, + SECKEYPrivateKey ** privKey, + CERTCertificate ** cert) +{ + PRFileDesc *model_sock = NULL; + int rv; + SSLKEAType kea; + SECStatus secStatus; + + if (useModelSocket) { + model_sock = PR_NewTCPSocket(); + if (model_sock == NULL) { + errExit("PR_NewTCPSocket on model socket"); + } + model_sock = SSL_ImportFD(NULL, model_sock); + if (model_sock == NULL) { + errExit("SSL_ImportFD"); + } + } else { + model_sock = listen_sock = SSL_ImportFD(NULL, listen_sock); + if (listen_sock == NULL) { + errExit("SSL_ImportFD"); + } + } + + /* do SSL configuration. */ + /* all suites except RSA_NULL_MD5 are enabled by default */ + +#if 0 + /* This is supposed to be true by default. + ** Setting it explicitly should not be necessary. + ** Let's test and make sure that's true. + */ + rv = SSL_OptionSet(model_sock, SSL_SECURITY, 1); + if (rv < 0) { + errExit("SSL_OptionSet SSL_SECURITY"); + } +#endif + + rv = SSL_OptionSet(model_sock, SSL_ENABLE_SSL3, !disableSSL3); + if (rv != SECSuccess) { + errExit("error enabling SSLv3 "); + } + + rv = SSL_OptionSet(model_sock, SSL_ENABLE_TLS, !disableTLS); + if (rv != SECSuccess) { + errExit("error enabling TLS "); + } + + rv = SSL_OptionSet(model_sock, SSL_ROLLBACK_DETECTION, !disableRollBack); + if (rv != SECSuccess) { + errExit("error enabling RollBack detection "); + } + + for (kea = kt_rsa; kea < kt_kea_size; kea++) { + if (cert[kea] != NULL) { + secStatus = SSL_ConfigSecureServer(model_sock, + cert[kea], privKey[kea], kea); + if (secStatus != SECSuccess) + errExit("SSL_ConfigSecureServer"); + } + } + + if (bigBuf.data) { /* doing FDX */ + rv = SSL_OptionSet(model_sock, SSL_ENABLE_FDX, 1); + if (rv < 0) { + errExit("SSL_OptionSet SSL_ENABLE_FDX"); + } + } + + /* This cipher is not on by default. The Acceptance test + * would like it to be. Turn this cipher on. + */ + + secStatus = SSL_CipherPrefSetDefault( SSL_RSA_WITH_NULL_MD5, PR_TRUE); + if ( secStatus != SECSuccess ) { + errExit("SSL_CipherPrefSetDefault:SSL_RSA_WITH_NULL_MD5"); + } + + + if (requestCert) { + SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate, + (void *)CERT_GetDefaultCertDB()); + if (requestCert <= 2) { + rv = SSL_OptionSet(model_sock, SSL_REQUEST_CERTIFICATE, 1); + if (rv < 0) { + errExit("first SSL_OptionSet SSL_REQUEST_CERTIFICATE"); + } + rv = SSL_OptionSet(model_sock, SSL_REQUIRE_CERTIFICATE, + (requestCert == 2)); + if (rv < 0) { + errExit("first SSL_OptionSet SSL_REQUIRE_CERTIFICATE"); + } + } + } + + if (MakeCertOK) + SSL_BadCertHook(model_sock, myBadCertHandler, NULL); + + /* end of ssl configuration. */ + + + /* Now, do the accepting, here in the main thread. */ + rv = do_accepts(listen_sock, model_sock, requestCert); + + terminateWorkerThreads(); + + if (useModelSocket && model_sock) { + PR_Close(model_sock); + } + +} + +SECStatus +readBigFile(const char * fileName) +{ + PRFileInfo info; + PRStatus status; + SECStatus rv = SECFailure; + int count; + int hdrLen; + PRFileDesc *local_file_fd = NULL; + + status = PR_GetFileInfo(fileName, &info); + + if (status == PR_SUCCESS && + info.type == PR_FILE_FILE && + info.size > 0 && + NULL != (local_file_fd = PR_Open(fileName, PR_RDONLY, 0))) { + + hdrLen = PORT_Strlen(outHeader); + bigBuf.len = hdrLen + info.size; + bigBuf.data = PORT_Malloc(bigBuf.len + 4095); + if (!bigBuf.data) { + errWarn("PORT_Malloc"); + goto done; + } + + PORT_Memcpy(bigBuf.data, outHeader, hdrLen); + + count = PR_Read(local_file_fd, bigBuf.data + hdrLen, info.size); + if (count != info.size) { + errWarn("PR_Read local file"); + goto done; + } + rv = SECSuccess; +done: + PR_Close(local_file_fd); + } + return rv; +} + +int numChildren; +PRProcess * child[MAX_PROCS]; + +PRProcess * +haveAChild(int argc, char **argv, PRProcessAttr * attr) +{ + PRProcess * newProcess; + + newProcess = PR_CreateProcess(argv[0], argv, NULL, attr); + if (!newProcess) { + errWarn("Can't create new process."); + } else { + child[numChildren++] = newProcess; + } + return newProcess; +} + +void +beAGoodParent(int argc, char **argv, int maxProcs, PRFileDesc * listen_sock) +{ + PRProcess * newProcess; + PRProcessAttr * attr; + int i; + PRInt32 exitCode; + PRStatus rv; + + rv = PR_SetFDInheritable(listen_sock, PR_TRUE); + if (rv != PR_SUCCESS) + errExit("PR_SetFDInheritable"); + + attr = PR_NewProcessAttr(); + if (!attr) + errExit("PR_NewProcessAttr"); + + rv = PR_ProcessAttrSetInheritableFD(attr, listen_sock, inheritableSockName); + if (rv != PR_SUCCESS) + errExit("PR_ProcessAttrSetInheritableFD"); + + for (i = 0; i < maxProcs; ++i) { + newProcess = haveAChild(argc, argv, attr); + if (!newProcess) + break; + } + + rv = PR_SetFDInheritable(listen_sock, PR_FALSE); + if (rv != PR_SUCCESS) + errExit("PR_SetFDInheritable"); + + while (numChildren > 0) { + newProcess = child[numChildren - 1]; + PR_WaitProcess(newProcess, &exitCode); + fprintf(stderr, "Child %d exited with exit code %x\n", + numChildren, exitCode); + numChildren--; + } + exit(0); +} + +#ifdef DEBUG_nelsonb + +#if defined(XP_UNIX) || defined(XP_OS2) || defined(XP_BEOS) +#define SSL_GETPID getpid +#elif defined(_WIN32_WCE) +#define SSL_GETPID GetCurrentProcessId +#elif defined(WIN32) +extern int __cdecl _getpid(void); +#define SSL_GETPID _getpid +#else +#define SSL_GETPID() 0 +#endif + +void +WaitForDebugger(void) +{ + + int waiting = 12; + int myPid = SSL_GETPID(); + PRIntervalTime nrval = PR_SecondsToInterval(5); + + while (waiting) { + printf("child %d is waiting to be debugged!\n", myPid); + PR_Sleep(nrval); + --waiting; + } +} +#endif + +int +main(int argc, char **argv) +{ + char * progName = NULL; + char * nickName = NULL; + char * fNickName = NULL; + const char * fileName = NULL; + char * cipherString= NULL; + const char * dir = "."; + char * passwd = NULL; + const char * pidFile = NULL; + char * tmp; + char * envString; + PRFileDesc * listen_sock; + CERTCertificate * cert [kt_kea_size] = { NULL }; + SECKEYPrivateKey * privKey[kt_kea_size] = { NULL }; + int optionsFound = 0; + int maxProcs = 1; + unsigned short port = 0; + SECStatus rv; + PRStatus prStatus; + PRBool bindOnly = PR_FALSE; + PRBool useExportPolicy = PR_FALSE; + PRBool useLocalThreads = PR_FALSE; + PLOptState *optstate; + PLOptStatus status; + PRThread *loggerThread; + PRBool debugCache = PR_FALSE; /* bug 90518 */ + + + tmp = strrchr(argv[0], '/'); + tmp = tmp ? tmp + 1 : argv[0]; + progName = strrchr(tmp, '\\'); + progName = progName ? progName + 1 : tmp; + + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + + /* please keep this list of options in ASCII collating sequence. + ** numbers, then capital letters, then lower case, alphabetical. + */ + optstate = PL_CreateOptState(argc, argv, + "2:3DL:M:RTbc:d:f:hi:lmn:op:rt:vw:xy"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + ++optionsFound; + switch(optstate->option) { + case '2': fileName = optstate->value; break; + + case '3': disableSSL3 = PR_TRUE; break; + + case 'D': noDelay = PR_TRUE; break; + + case 'L': + logStats = PR_TRUE; + if (optstate->value == NULL) { + logPeriod = 30; + } else { + logPeriod = PORT_Atoi(optstate->value); + if (logPeriod <= 0) logPeriod = 30; + } + break; + + case 'M': + maxProcs = PORT_Atoi(optstate->value); + if (maxProcs < 1) maxProcs = 1; + if (maxProcs > MAX_PROCS) maxProcs = MAX_PROCS; + break; + + case 'R': disableRollBack = PR_TRUE; break; + + case 'T': disableTLS = PR_TRUE; break; + + case 'b': bindOnly = PR_TRUE; break; + + case 'c': cipherString = strdup(optstate->value); break; + + case 'd': dir = optstate->value; break; + + case 'f': fNickName = strdup(optstate->value); break; + + case 'h': Usage(progName); exit(0); break; + + case 'i': pidFile = optstate->value; break; + + case 'l': useLocalThreads = PR_TRUE; break; + + case 'm': useModelSocket = PR_TRUE; break; + + case 'n': nickName = strdup(optstate->value); break; + + case 'o': MakeCertOK = 1; break; + + case 'p': port = PORT_Atoi(optstate->value); break; + + case 'r': ++requestCert; break; + + case 't': + maxThreads = PORT_Atoi(optstate->value); + if ( maxThreads > MAX_THREADS ) maxThreads = MAX_THREADS; + if ( maxThreads < MIN_THREADS ) maxThreads = MIN_THREADS; + break; + + case 'v': verbose++; break; + + case 'w': passwd = strdup(optstate->value); break; + + case 'x': useExportPolicy = PR_TRUE; break; + + case 'y': debugCache = PR_TRUE; break; + + default: + case '?': + fprintf(stderr, "Unrecognized or bad option specified.\n"); + fprintf(stderr, "Run '%s -h' for usage information.\n", progName); + exit(4); + break; + } + } + PL_DestroyOptState(optstate); + if (status == PL_OPT_BAD) { + fprintf(stderr, "Unrecognized or bad option specified.\n"); + fprintf(stderr, "Run '%s -h' for usage information.\n", progName); + exit(5); + } + if (!optionsFound) { + Usage(progName); + exit(51); + } + + /* The -b (bindOnly) option is only used by the ssl.sh test + * script on Linux to determine whether a previous selfserv + * process has fully died and freed the port. (Bug 129701) + */ + if (bindOnly) { + listen_sock = getBoundListenSocket(port); + if (!listen_sock) { + exit(1); + } + PR_Close(listen_sock); + exit(0); + } + + if ((nickName == NULL) && (fNickName == NULL)) { + fprintf(stderr, "Required arg '-n' (rsa nickname) not supplied.\n"); + fprintf(stderr, "Run '%s -h' for usage information.\n", progName); + exit(6); + } + + if (port == 0) { + fprintf(stderr, "Required argument 'port' must be non-zero value\n"); + exit(7); + } + + if (pidFile) { + FILE *tmpfile=fopen(pidFile,"w+"); + + if (tmpfile) { + fprintf(tmpfile,"%d",getpid()); + fclose(tmpfile); + } + } + + envString = getenv(envVarName); + tmp = getenv("TMP"); + if (!tmp) + tmp = getenv("TMPDIR"); + if (!tmp) + tmp = getenv("TEMP"); + if (envString) { + /* we're one of the children in a multi-process server. */ + listen_sock = PR_GetInheritedFD(inheritableSockName); + if (!listen_sock) + errExit("PR_GetInheritedFD"); +#ifndef WINNT + /* we can't do this on NT because it breaks NSPR and + PR_Accept will fail on the socket in the child process if + the socket state is change to non inheritable + It is however a security issue to leave it accessible, + but it is OK for a test server such as selfserv. + NSPR should fix it eventually . see bugzilla 101617 + and 102077 + */ + prStatus = PR_SetFDInheritable(listen_sock, PR_FALSE); + if (prStatus != PR_SUCCESS) + errExit("PR_SetFDInheritable"); +#endif +#ifdef DEBUG_nelsonb + WaitForDebugger(); +#endif + rv = SSL_InheritMPServerSIDCache(envString); + if (rv != SECSuccess) + errExit("SSL_InheritMPServerSIDCache"); + } else if (maxProcs > 1) { + /* we're going to be the parent in a multi-process server. */ + listen_sock = getBoundListenSocket(port); + rv = SSL_ConfigMPServerSIDCache(NUM_SID_CACHE_ENTRIES, 0, 0, tmp); + if (rv != SECSuccess) + errExit("SSL_ConfigMPServerSIDCache"); + beAGoodParent(argc, argv, maxProcs, listen_sock); + exit(99); /* should never get here */ + } else { + /* we're an ordinary single process server. */ + listen_sock = getBoundListenSocket(port); + prStatus = PR_SetFDInheritable(listen_sock, PR_FALSE); + if (prStatus != PR_SUCCESS) + errExit("PR_SetFDInheritable"); + rv = SSL_ConfigServerSessionIDCache(NUM_SID_CACHE_ENTRIES, 0, 0, tmp); + if (rv != SECSuccess) + errExit("SSL_ConfigServerSessionIDCache"); + } + + lm = PR_NewLogModule("TestCase"); + + if (fileName) + readBigFile(fileName); + + /* set our password function */ + PK11_SetPasswordFunc( passwd ? ownPasswd : SECU_GetModulePassword); + + /* Call the libsec initialization routines */ + rv = NSS_Init(dir); + if (rv != SECSuccess) { + fputs("NSS_Init failed.\n", stderr); + exit(8); + } + + /* set the policy bits true for all the cipher suites. */ + if (useExportPolicy) + NSS_SetExportPolicy(); + else + NSS_SetDomesticPolicy(); + + /* all the SSL2 and SSL3 cipher suites are enabled by default. */ + if (cipherString) { + int ndx; + + /* disable all the ciphers, then enable the ones we want. */ + disableAllSSLCiphers(); + + while (0 != (ndx = *cipherString++)) { + const int *cptr; + int cipher; + + if (! isalpha(ndx)) { + fprintf(stderr, + "Non-alphabetic char in cipher string (-c arg).\n"); + exit(9); + } + cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites; + for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; ) + /* do nothing */; + if (cipher) { + SECStatus status; + status = SSL_CipherPrefSetDefault(cipher, SSL_ALLOWED); + if (status != SECSuccess) + SECU_PrintError(progName, "SSL_CipherPrefSet()"); + } + } + } + + if (nickName) { + cert[kt_rsa] = PK11_FindCertFromNickname(nickName, passwd); + if (cert[kt_rsa] == NULL) { + fprintf(stderr, "selfserv: Can't find certificate %s\n", nickName); + exit(10); + } + privKey[kt_rsa] = PK11_FindKeyByAnyCert(cert[kt_rsa], passwd); + if (privKey[kt_rsa] == NULL) { + fprintf(stderr, "selfserv: Can't find Private Key for cert %s\n", + nickName); + exit(11); + } + } + if (fNickName) { + cert[kt_fortezza] = PK11_FindCertFromNickname(fNickName, NULL); + if (cert[kt_fortezza] == NULL) { + fprintf(stderr, "selfserv: Can't find certificate %s\n", fNickName); + exit(12); + } + privKey[kt_fortezza] = PK11_FindKeyByAnyCert(cert[kt_fortezza], NULL); + } + + /* allocate the array of thread slots, and launch the worker threads. */ + rv = launch_threads(&jobLoop, 0, 0, requestCert, useLocalThreads); + + if (rv == SECSuccess && logStats) { + loggerThread = PR_CreateThread(PR_SYSTEM_THREAD, + logger, NULL, PR_PRIORITY_NORMAL, + useLocalThreads ? PR_LOCAL_THREAD:PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (loggerThread == NULL) { + fprintf(stderr, "selfserv: Failed to launch logger thread!\n"); + rv = SECFailure; + } + } + + if (rv == SECSuccess) { + server_main(listen_sock, requestCert, privKey, cert); + } + + VLOG(("selfserv: server_thread: exiting")); + + { + int i; + for (i=0; i<kt_kea_size; i++) { + if (cert[i]) { + CERT_DestroyCertificate(cert[i]); + } + if (privKey[i]) { + SECKEY_DestroyPrivateKey(privKey[i]); + } + } + } + + if (debugCache) { + nss_DumpCertificateCacheInfo(); + } + + free(nickName); + free(passwd); + + SSL_ShutdownServerSessionIDCache(); + + if (NSS_Shutdown() != SECSuccess) { + SECU_PrintError(progName, "NSS_Shutdown"); + PR_Cleanup(); + exit(1); + } + PR_Cleanup(); + printf("selfserv: normal termination\n"); + return 0; +} diff --git a/security/nss/cmd/shlibsign/Makefile b/security/nss/cmd/shlibsign/Makefile new file mode 100644 index 000000000..11b458de9 --- /dev/null +++ b/security/nss/cmd/shlibsign/Makefile @@ -0,0 +1,110 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +# +# we really should have this driven from a list file made during the normal +# NSS build prodecure. +# +ifndef USE_64 +ifeq ($(OS_TARGET), HP-UX) + ifneq ($(OS_TEST), ia64) + LOADABLE_FREEBL= 1 + endif +endif +ifeq ($(OS_TARGET), SunOS) + ifeq ($(CPU_ARCH), sparc) + LOADABLE_FREEBL = 1 + endif +endif +endif + +ifdef LOADABLE_FREEBL + CHECKFILES += freebl_pure32_3.chk freebl_hybrid_3.chk +endif + +CHECKLOC=$(addprefix $(DIST)/lib/$(DLL_PREFIX), $(CHECKFILES)) + +MD_LIB_RELEASE_FILES = $(CHECKLOC) +ALL_TRASH += $(CHECKLOC) + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + +%.chk: %.$(DLL_SUFFIX) +ifeq ($(OS_TARGET), OS2) + @cmd.exe /c sign.cmd $(DIST) $(OBJDIR) $(OS_TARGET) $< +else + @sh ./sign.sh $(DIST) $(OBJDIR) $(OS_TARGET) $< +endif + +libs install :: $(CHECKLOC) + diff --git a/security/nss/cmd/shlibsign/mangle/Makefile b/security/nss/cmd/shlibsign/mangle/Makefile new file mode 100644 index 000000000..7948a4328 --- /dev/null +++ b/security/nss/cmd/shlibsign/mangle/Makefile @@ -0,0 +1,75 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../../platlibs.mk + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../../platrules.mk + diff --git a/security/nss/cmd/shlibsign/mangle/mangle.c b/security/nss/cmd/shlibsign/mangle/mangle.c new file mode 100644 index 000000000..7ff34b5e6 --- /dev/null +++ b/security/nss/cmd/shlibsign/mangle/mangle.c @@ -0,0 +1,166 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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-2003 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. + */ + +/* + * Test program to mangle 1 bit in a binary + * + * $Id$ + */ + +#include "nspr.h" +#include "plstr.h" +#include "plgetopt.h" +#include "prio.h" + +static PRFileDesc *pr_stderr; +static void +usage (char *program_name) +{ + + PR_fprintf (pr_stderr, "Usage:"); + PR_fprintf (pr_stderr, "%s -i shared_library_name -o byte_offset -b bit\n", program_name); +} + + +int +main (int argc, char **argv) +{ + /* buffers and locals */ + PLOptState *optstate; + char *programName; + char cbuf; + + /* parameter set variables */ + const char *libFile = NULL; + int offset = -1; + int bitOffset = -1; + + /* return values */ + int retval = 2; /* 0 - test succeeded. + * 1 - illegal args + * 2 - function failed */ + PRFileDesc *fd; + int bytesRead; + int bytesWritten; + int pos; + + programName = PL_strrchr(argv[0], '/'); + programName = programName ? (programName + 1) : argv[0]; + + pr_stderr = PR_STDERR; + + optstate = PL_CreateOptState (argc, argv, "i:o:b:"); + if (optstate == NULL) { + return 1; + } + + while (PL_GetNextOpt (optstate) == PL_OPT_OK) { + switch (optstate->option) { + case 'i': + libFile = optstate->value; + break; + + case 'o': + offset = atoi(optstate->value); + break; + + case 'b': + bitOffset = atoi(optstate->value); + break; + } + } + + if (libFile == NULL) { + usage(programName); + return 1; + } + if ((bitOffset >= 8) || (bitOffset < 0)) { + usage(programName); + return 1; + } + + if (offset < 0) { + usage(programName); + return 1; + } + + /* open the target signature file */ + fd = PR_OpenFile(libFile,PR_RDWR,0666); + if (fd == NULL ) { + /* lperror(libFile); */ + PR_fprintf(pr_stderr,"Couldn't Open %s\n",libFile); + goto loser; + } + + /* read the byte */ + pos = PR_Seek(fd, offset, PR_SEEK_SET); + if (pos != offset) { + PR_fprintf(pr_stderr,"Seek for read on %s (to %d) failed\n", libFile, offset); + goto loser; + } + bytesRead = PR_Read(fd, &cbuf, 1); + if (bytesRead != 1) { + PR_fprintf(pr_stderr,"Read on %s (to %d) failed\n", libFile, offset); + goto loser; + } + + PR_fprintf(pr_stderr,"Changing byte 0x%08x (%d): from %02x (%d) to ", + offset, offset, (unsigned char)cbuf, (unsigned char)cbuf); + /* change it */ + cbuf ^= 1 << bitOffset; + PR_fprintf(pr_stderr,"%02x (%d)\n", ( + unsigned char)cbuf, (unsigned char)cbuf); + + /* write it back out */ + pos = PR_Seek(fd, offset, PR_SEEK_SET); + if (pos != offset) { + PR_fprintf(pr_stderr,"Seek for write on %s (to %d) failed\n", libFile, offset); + goto loser; + } + bytesWritten = PR_Write(fd, &cbuf, 1); + if (bytesWritten != 1) { + PR_fprintf(pr_stderr,"Write on %s (to %d) failed\n", libFile, offset); + goto loser; + } + + PR_Close(fd); + retval = 0; + + +loser: + + PR_Cleanup (); + return retval; +} + +/*#DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\" */ diff --git a/security/nss/cmd/shlibsign/mangle/manifest.mn b/security/nss/cmd/shlibsign/mangle/manifest.mn new file mode 100644 index 000000000..d850921f0 --- /dev/null +++ b/security/nss/cmd/shlibsign/mangle/manifest.mn @@ -0,0 +1,52 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\" + +CSRCS = \ + mangle.c \ + $(NULL) + + +# headers for the MODULE (defined above) are implicitly required. +REQUIRES = + +PROGRAM = mangle + +USE_STATIC_LIBS = 1 + diff --git a/security/nss/cmd/shlibsign/manifest.mn b/security/nss/cmd/shlibsign/manifest.mn new file mode 100644 index 000000000..40cdeeff1 --- /dev/null +++ b/security/nss/cmd/shlibsign/manifest.mn @@ -0,0 +1,60 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +DEFINES += -DSHLIB_SUFFIX=\"$(DLL_SUFFIX)\" -DSHLIB_PREFIX=\"$(DLL_PREFIX)\" + +CSRCS = \ + shlibsign.c \ + $(NULL) + +CHECKFILES = softokn3.chk + +# headers for the MODULE (defined above) are implicitly required. +REQUIRES = dbm seccmd + +# WINNT uses EXTRA_LIBS as the list of libs to link in. +# Unix uses OS_LIBS for that purpose. +# We can solve this via conditional makefile code, but +# can't do this in manifest.mn because OS_ARCH isn't defined there. +# So, look in the local Makefile for the defines for the list of libs. + +PROGRAM = shlibsign + +DIRS = mangle + +#USE_STATIC_LIBS = 1 diff --git a/security/nss/cmd/shlibsign/shlibsign.c b/security/nss/cmd/shlibsign/shlibsign.c new file mode 100644 index 000000000..6d4af89b4 --- /dev/null +++ b/security/nss/cmd/shlibsign/shlibsign.c @@ -0,0 +1,427 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* + * Test program for SDR (Secret Decoder Ring) functions. + * + * $Id$ + */ + +#ifdef XP_UNIX +#define USES_LINKS 1 +#endif + +#include "nspr.h" +#include <stdio.h> +#include "nss.h" +#include "secutil.h" +#include "cert.h" +#include "pk11func.h" + +#include "plgetopt.h" +#include "pk11sdr.h" +#include "secrng.h" +#include "shsign.h" +#include "pk11pqg.h" + +#ifdef USES_LINKS +#include <unistd.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/stat.h> +#endif + +static void +usage (char *program_name) +{ + PRFileDesc *pr_stderr; + + pr_stderr = PR_STDERR; + PR_fprintf (pr_stderr, "Usage:"); + PR_fprintf (pr_stderr, "%s [-v] -i shared_library_name\n", program_name); +} + +static char * +mkoutput(const char *input) +{ + int in_len = PORT_Strlen(input); + char *output = PORT_Alloc(in_len+sizeof(SGN_SUFFIX)); + int index = in_len + 1 - sizeof("."SHLIB_SUFFIX); + + if ((index > 0) && + (PORT_Strncmp(&input[index], + "."SHLIB_SUFFIX,sizeof("."SHLIB_SUFFIX)) == 0)) { + in_len = index; + } + PORT_Memcpy(output,input,in_len); + PORT_Memcpy(&output[in_len],SGN_SUFFIX,sizeof(SGN_SUFFIX)); + return output; +} + + +static void +lperror(const char *string) +{ + int errNum = PORT_GetError(); + const char *error = SECU_Strerror(errNum); + fprintf(stderr,"%s: %s\n",string, error); +} + +static void +encodeInt(unsigned char *buf, int val) +{ + buf[3] = (val >> 0) & 0xff; + buf[2] = (val >> 8) & 0xff; + buf[1] = (val >> 16) & 0xff; + buf[0] = (val >> 24) & 0xff; + return; +} + +static SECStatus +writeItem(PRFileDesc *fd, SECItem *item, char *file) +{ + unsigned char buf[4]; + int bytesWritten; + + encodeInt(buf,item->len); + bytesWritten = PR_Write(fd,buf, 4); + if (bytesWritten != 4) { + lperror(file); + return SECFailure; + } + bytesWritten = PR_Write(fd, item->data, item->len); + if (bytesWritten != item->len) { + lperror(file); + return SECFailure; + } + return SECSuccess; +} + + +int +main (int argc, char **argv) +{ + int retval = 1; /* 0 - test succeeded. 1 - test failed */ + SECStatus rv; + PLOptState *optstate; + char *program_name; + const char *input_file = NULL; /* read encrypted data from here (or create) */ + char *output_file = NULL; /* write new encrypted data here */ + PRBool verbose = PR_FALSE; + SECKEYPrivateKey *privk = NULL; + SECKEYPublicKey *pubk = NULL; + PK11SlotInfo *slot = NULL; + PRFileDesc *fd; + int bytesRead; + int bytesWritten; + unsigned char file_buf[512]; + unsigned char hash_buf[SHA1_LENGTH]; + unsigned char sign_buf[40]; /* DSA_LENGTH */ + SECItem hash,sign; + PK11Context *hashcx = NULL; + int ks, count=0; + int keySize = 1024; + PQGParams *pqgParams = NULL; + PQGVerify *pqgVerify = NULL; +#ifdef USES_LINKS + int ret; + struct stat stat_buf; + char link_buf[MAXPATHLEN+1]; + char *link_file = NULL; +#endif + + hash.len = sizeof(hash_buf); hash.data = hash_buf; + sign.len = sizeof(sign_buf); sign.data = sign_buf; + + program_name = PL_strrchr(argv[0], '/'); + program_name = program_name ? (program_name + 1) : argv[0]; + + optstate = PL_CreateOptState (argc, argv, "d:i:o:v"); + if (optstate == NULL) { + SECU_PrintError (program_name, "PL_CreateOptState failed"); + return 1; + } + + while (PL_GetNextOpt (optstate) == PL_OPT_OK) { + switch (optstate->option) { +#ifdef notdef + case '?': + short_usage (program_name); + return 0; + + case 'H': + long_usage (program_name); + return 0; +#endif + + case 'd': + SECU_ConfigDirectory(optstate->value); + break; + + case 'i': + input_file = optstate->value; + break; + + case 'o': + output_file = PORT_Strdup(optstate->value); + break; + + case 'v': + verbose = PR_TRUE; + break; + } + } + + if (input_file == NULL) { + usage(program_name); + return 1; + } + + /* + * Initialize the Security libraries. + */ + PK11_SetPasswordFunc(SECU_GetModulePassword); + + rv = NSS_Init(SECU_ConfigDirectory(NULL)); + if (rv != SECSuccess) { + rv = NSS_NoDB_Init(""); + } + if (rv != SECSuccess) { + lperror("NSS_Init failed"); + goto prdone; + } + + /* Generate a DSA Key pair */ + slot = PK11_GetBestSlot(CKM_DSA,NULL); + if (slot == NULL) { + lperror("CKM_DSA"); + goto loser; + + } + printf("Generating DSA Key Pair...."); fflush(stdout); + ks = PQG_PBITS_TO_INDEX(keySize); + rv = PK11_PQG_ParamGen(ks,&pqgParams, &pqgVerify); + if (rv != SECSuccess) { + lperror("Generating PQG Params"); + goto loser; + } + privk = PK11_GenerateKeyPair(slot, CKM_DSA_KEY_PAIR_GEN, pqgParams, &pubk, + PR_FALSE, PR_TRUE, NULL); + if (privk == NULL) { + lperror("Generating DSA Key"); + goto loser; + } + + printf("done\n"); + + /* open the shared library */ + fd = PR_OpenFile(input_file,PR_RDONLY,0); + if (fd == NULL ) { + lperror(input_file); + goto loser; + } +#ifdef USES_LINKS + ret = lstat(input_file, &stat_buf); + if (ret < 0) { + perror(input_file); + goto loser; + } + if (S_ISLNK(stat_buf.st_mode)) { + char *dirpath,*dirend; + ret = readlink(input_file, link_buf, sizeof(link_buf) - 1); + if (ret < 0) { + perror(input_file); + goto loser; + } + link_buf[ret] = 0; + link_file = mkoutput(input_file); + /* get the dirname of input_file */ + dirpath = PORT_Strdup(input_file); + dirend = PORT_Strrchr(dirpath, '/'); + if (dirend) { + *dirend = '\0'; + ret = chdir(dirpath); + if (ret < 0) { + perror(dirpath); + goto loser; + } + } + PORT_Free(dirpath); + input_file = link_buf; + /* get the basename of link_file */ + dirend = PORT_Strrchr(link_file, '/'); + if (dirend) { + link_file = dirend + 1; + } + } +#endif + if (output_file == NULL) { + output_file = mkoutput(input_file); + } + + hashcx = PK11_CreateDigestContext(SEC_OID_SHA1); + if (hashcx == NULL) { + lperror("SHA1 Digest Create"); + goto loser; + } + + /* hash the file */ + while ((bytesRead = PR_Read(fd,file_buf,sizeof(file_buf))) > 0) { + PK11_DigestOp(hashcx,file_buf,bytesRead); + count += bytesRead; + } + + PR_Close(fd); + fd = NULL; + if (bytesRead < 0) { + lperror(input_file); + goto loser; + } + + + PK11_DigestFinal(hashcx, hash.data, &hash.len, hash.len); + + if (hash.len != SHA1_LENGTH) { + fprintf(stderr, "Digest length was not correct\n"); + goto loser; + } + + /* signe the hash */ + rv = PK11_Sign(privk,&sign,&hash); + if (rv != SECSuccess) { + lperror("Signing"); + goto loser; + } + + if (verbose) { + int i,j; + fprintf(stderr,"Library File: %s %d bytes\n",input_file, count); + fprintf(stderr,"Check File: %s\n",output_file); +#ifdef USES_LINKS + if (link_file) { + fprintf(stderr,"Link: %s\n",link_file); + } +#endif + fprintf(stderr," hash: %d bytes\n", hash.len); +#define STEP 10 + for (i=0; i < hash.len; i += STEP) { + fprintf(stderr," "); + for (j=0; j < STEP && (i+j) < hash.len; j++) { + fprintf(stderr," %02x", hash.data[i+j]); + } + fprintf(stderr,"\n"); + } + fprintf(stderr," signature: %d bytes\n", sign.len); + for (i=0; i < sign.len; i += STEP) { + fprintf(stderr," "); + for (j=0; j < STEP && (i+j) < sign.len; j++) { + fprintf(stderr," %02x", sign.data[i+j]); + } + fprintf(stderr,"\n"); + } + } + + /* open the target signature file */ + fd = PR_OpenFile(output_file,PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE,0666); + if (fd == NULL ) { + lperror(output_file); + goto loser; + } + + /* + * we write the key out in a straight binary format because very + * low level libraries need to read an parse this file. Ideally we should + * just derEncode the public key (which would be pretty simple, and be + * more general), but then we'd need to link the ASN.1 decoder with the + * freebl libraries. + */ + + file_buf[0] = NSS_SIGN_CHK_MAGIC1; + file_buf[1] = NSS_SIGN_CHK_MAGIC2; + file_buf[2] = NSS_SIGN_CHK_MAJOR_VERSION; + file_buf[3] = NSS_SIGN_CHK_MINOR_VERSION; + encodeInt(&file_buf[4],12); /* offset to data start */ + encodeInt(&file_buf[8],CKK_DSA); + bytesWritten = PR_Write(fd,file_buf, 12); + if (bytesWritten != 12) { + lperror(output_file); + goto loser; + } + + rv = writeItem(fd,&pubk->u.dsa.params.prime,output_file); + if (rv != SECSuccess) goto loser; + rv = writeItem(fd,&pubk->u.dsa.params.subPrime,output_file); + if (rv != SECSuccess) goto loser; + rv = writeItem(fd,&pubk->u.dsa.params.base,output_file); + if (rv != SECSuccess) goto loser; + rv = writeItem(fd,&pubk->u.dsa.publicValue,output_file); + if (rv != SECSuccess) goto loser; + rv = writeItem(fd,&sign,output_file); + if (rv != SECSuccess) goto loser; + + PR_Close(fd); + +#ifdef USES_LINKS + if (link_file) { + (void)unlink(link_file); + ret = symlink(output_file, link_file); + if (ret < 0) { + perror(link_file); + goto loser; + } + } +#endif + + retval = 0; + +loser: + if (hashcx) { + PK11_DestroyContext(hashcx, PR_TRUE); + } + if (privk) { + SECKEY_DestroyPrivateKey(privk); + } + if (pubk) { + SECKEY_DestroyPublicKey(pubk); + } + if (slot) { + PK11_FreeSlot(slot); + } + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + +prdone: + PR_Cleanup (); + return retval; +} diff --git a/security/nss/cmd/shlibsign/sign.cmd b/security/nss/cmd/shlibsign/sign.cmd new file mode 100644 index 000000000..612609de9 --- /dev/null +++ b/security/nss/cmd/shlibsign/sign.cmd @@ -0,0 +1,19 @@ +/* Equivalent to sign.sh for OS/2 */ +PARSE ARG dist objdir os_target therest +dist=forwardtoback(dist); +objdir=forwardtoback(objdir); +'echo 'dist +'echo 'objdir +'set BEGINLIBPATH='dist'\lib;%BEGINLIBPATH%' +'set LIBPATHSTRICT=T' +objdir'\shlibsign -v -i 'therest +exit + +forwardtoback: procedure + arg pathname + parse var pathname pathname'/'rest + do while (rest <> "") + pathname = pathname'\'rest + parse var pathname pathname'/'rest + end + return pathname diff --git a/security/nss/cmd/shlibsign/sign.sh b/security/nss/cmd/shlibsign/sign.sh new file mode 100644 index 000000000..9a5d79fc9 --- /dev/null +++ b/security/nss/cmd/shlibsign/sign.sh @@ -0,0 +1,51 @@ +#!/bin/sh +case "${3}" in +WIN*) + if echo "${PATH}" | grep -c \; >/dev/null; then + PATH=${PATH}\;${1}/bin\;${1}/lib + else + # ARG1 is ${1} with the drive letter escaped. + if echo "${1}" | grep -c : >/dev/null; then + ARG1=`(cd ${1}; pwd)` + else + ARG1=${1} + fi + PATH=${PATH}:${ARG1}/bin:${ARG1}/lib + fi + export PATH + echo ${2}/shlibsign -v -i ${4} + ${2}/shlibsign -v -i ${4} + ;; +OpenVMS) + temp="tmp$$.tmp" + temp2="tmp$$.tmp2" + cd ${1}/lib + vmsdir=`dcl show default` + ls *.so > $temp + sed -e "s/\([^\.]*\)\.so/\$ define\/job \1 ${vmsdir}\1.so/" $temp > $temp2 + echo '$ define/job getipnodebyname xxx' >> $temp2 + echo '$ define/job vms_null_dl_name sys$share:decc$shr' >> $temp2 + dcl @$temp2 + echo ${2}/shlibsign -v -i ${4} + ${2}/shlibsign -v -i ${4} + sed -e "s/\([^\.]*\)\.so/\$ deass\/job \1/" $temp > $temp2 + echo '$ deass/job getipnodebyname' >> $temp2 + echo '$ deass/job vms_null_dl_name' >> $temp2 + dcl @$temp2 + rm $temp $temp2 + ;; +*) + LIBPATH=`(cd ${1}/lib; pwd)`:$LIBPATH + export LIBPATH + SHLIB_PATH=${1}/lib:$SHLIB_PATH + export SHLIB_PATH + LD_LIBRARY_PATH=${1}/lib:$LD_LIBRARY_PATH + export LD_LIBRARY_PATH + DYLD_LIBRARY_PATH=${1}/lib:$DYLD_LIBRARY_PATH + export DYLD_LIBRARY_PATH + LIBRARY_PATH=${1}/lib:$LIBRARY_PATH + export LIBRARY_PATH + echo ${2}/shlibsign -v -i ${4} + ${2}/shlibsign -v -i ${4} + ;; +esac diff --git a/security/nss/cmd/signtool/Makefile b/security/nss/cmd/signtool/Makefile new file mode 100644 index 000000000..e4a3a6069 --- /dev/null +++ b/security/nss/cmd/signtool/Makefile @@ -0,0 +1,71 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +include ../platrules.mk diff --git a/security/nss/cmd/signtool/README b/security/nss/cmd/signtool/README new file mode 100644 index 000000000..2bdb705c7 --- /dev/null +++ b/security/nss/cmd/signtool/README @@ -0,0 +1,119 @@ + Signing Tool (signtool) + 1.3 Release Notes + ======================================== + +Documentation is provided online at mozilla.org + +Problems or questions not covered by the online documentation can be +discussed in the DevEdge Security Newsgroup. + +=== New Features in 1.3 +======================= + +The security library components have been upgraded to utilize NSS_2_7_1_RTM. +This means that the maximum RSA keysize now supported should be 4096 bits. + +=== Zigbert 0.6 Support +======================= +This program was previously named Zigbert. The last version of zigbert +was Zigbert 0.6. Because all the functionality of Zigbert is maintained in +signtool 1.2, Zigbert is no longer supported. If you have problems +using Zigbert, please upgrade to signtool 1.2. + +=== New Features in 1.2 +======================= + +Certificate Generation Improvements +----------------------------------- +Two new options have been added to control generation of self-signed object +signing certificates with the -G option. The -s option takes the size (in bits) +of the generated RSA private key. The -t option takes the name of the PKCS #11 +token on which to generate the keypair and install the certificate. Both +options are optional. By default, the private key is 1024 bits and is generated +on the internal software token. + + +=== New Features in 1.1 +======================= + +File I/O +-------- +Signtool can now read its options from a command file specified with the -f +option on the command line. The format for the file is described in the +documentation. +Error messages and informational output can be redirected to an output file +by supplying the "--outfile" option on the command line or the "outfile=" +option in the command file. + +New Options +----------- +"--norecurse" tells Signtool not to recurse into subdirectories when signing +directories or parsing HTML with the -J option. +"--leavearc" tells Signtool not to delete the temporary .arc directories +produced by the -J option. This can aid debugging. +"--verbosity" tells Signtool how much information to display. 0 is the +default. -1 suppresses most messages, except for errors. + +=== Bug Fixes in 1.1 +==================== + +-J option revamped +------------------ +The -J option, which parses HTML files, extracts Java and Javascript code, +and stores them in signed JAR files, has been re-implemented. Several bugs +have been fixed: +- CODEBASE attribute is no longer ignored +- CLASS and SRC attributes can be be paths ("xxx/xxx/x.class") rather than + just filenames ("x.class"). +- LINK tags are handled correctly +- various HTML parsing bugs fixed +- error messages are more informative + +No Password on Key Database +--------------------------- +If you had not yet set a Communicator password (which locks key3.db, the +key database), signtool would fail with a cryptic error message whenever it +attempted to verify the password. Now this condition is detected at the +beginning of the program, and a more informative message is displayed. + +-x and -e Options +----------------- +Previously, only one of each of these options could be specified on the command +line. Now arbitrarily many can be specified. For example, to sign only files +with .class or .js extensions, the arguments "-eclass -ejs" could both be +specified. To exclude the directories "subdir1" and "subdir2" from signing, +the arguments "-x subdir1 -x subdir2" could both be specified. + +New Features in 1.0 +=================== + +Creation of JAR files +---------------------- +The -Z option causes signtool to output a JAR file formed by storing the +signed archive in ZIP format. This eliminates the need to use a separate ZIP +utility. The -c option specifies the compression level of the resulting +JAR file. + +Generation of Object-Signing Certificates and Keys +-------------------------------------------------- +The -G option will create a new, self-signed object-signing certificate +which can be used for testing purposes. The generated certificate and +associated public and private keys will be installed in the cert7.db and +key3.db files in the directory specified with the -d option (unless the key +is generated on an external token using the -t option). On Unix systems, +if no directory is specified, the user's Netscape directory (~/.netscape) +will be used. In addition, the certificate is output in X509 format to the +files x509.raw and x509.cacert in the current directory. x509.cacert can +be published on a web page and imported into browsers that visit that page. + +Extraction and Signing of JavaScript from HTML +---------------------------------------------- +The -J option activates the same functionality provided by the signpages +Perl script. It will parse a directory of html files, creating archives +of the JavaScript called from the HTML. These archives are then signed and +made into JAR files. + +Enhanced Smart Card Support +--------------------------- +Certificates that reside on smart cards are displayed when using the -L and +-l options. diff --git a/security/nss/cmd/signtool/certgen.c b/security/nss/cmd/signtool/certgen.c new file mode 100644 index 000000000..4687a7841 --- /dev/null +++ b/security/nss/cmd/signtool/certgen.c @@ -0,0 +1,713 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "signtool.h" + +#include "secoid.h" +#include "cryptohi.h" +#include "certdb.h" + +static char* GetSubjectFromUser(unsigned long serial); +static CERTCertificate* GenerateSelfSignedObjectSigningCert(char *nickname, + CERTCertDBHandle *db, char *subject, unsigned long serial, int keysize, + char *token); +static SECStatus ChangeTrustAttributes(CERTCertDBHandle *db, + CERTCertificate *cert, char *trusts); +static SECStatus set_cert_type(CERTCertificate *cert, unsigned int type); +static SECItem *sign_cert(CERTCertificate *cert, SECKEYPrivateKey *privk); +static CERTCertificate* install_cert(CERTCertDBHandle *db, SECItem *derCert, + char *nickname); +static SECStatus GenerateKeyPair(PK11SlotInfo *slot, SECKEYPublicKey **pubk, + SECKEYPrivateKey **privk, int keysize); +static CERTCertificateRequest* make_cert_request(char *subject, + SECKEYPublicKey *pubk); +static CERTCertificate * make_cert(CERTCertificateRequest *req, + unsigned long serial, CERTName *ca_subject); +static void output_ca_cert (CERTCertificate *cert, CERTCertDBHandle *db); + + +/*********************************************************************** + * + * G e n e r a t e C e r t + * + * Runs the whole process of creating a new cert, getting info from the + * user, etc. + */ +int +GenerateCert(char *nickname, int keysize, char *token) +{ + CERTCertDBHandle *db; + CERTCertificate *cert; + char *subject; + unsigned long serial; + char stdinbuf[160]; + + /* Print warning about having the browser open */ + PR_fprintf(PR_STDOUT /*always go to console*/, +"\nWARNING: Performing this operation while the browser is running could cause" +"\ncorruption of your security databases. If the browser is currently running," +"\nyou should exit the browser before continuing this operation. Enter " +"\n\"y\" to continue, or anything else to abort: "); + pr_fgets(stdinbuf, 160, PR_STDIN); + PR_fprintf(PR_STDOUT, "\n"); + if(tolower(stdinbuf[0]) != 'y') { + PR_fprintf(errorFD, "Operation aborted at user's request.\n"); + errorCount++; + return -1; + } + + db = CERT_GetDefaultCertDB(); + if(!db) { + FatalError("Unable to open certificate database"); + } + + if(PK11_FindCertFromNickname(nickname, NULL)) { + PR_fprintf(errorFD, +"ERROR: Certificate with nickname \"%s\" already exists in database. You\n" +"must choose a different nickname.\n", nickname); + errorCount++; + exit(ERRX); + } + + LL_L2UI(serial, PR_Now()); + + subject = GetSubjectFromUser(serial); + + cert = GenerateSelfSignedObjectSigningCert(nickname, db, subject, + serial, keysize, token); + + if(cert) { + output_ca_cert(cert, db); + CERT_DestroyCertificate(cert); + } + + PORT_Free(subject); + return 0; +} + +#undef VERBOSE_PROMPTS + +/*********************************************************************8 + * G e t S u b j e c t F r o m U s e r + * + * Construct the subject information line for a certificate by querying + * the user on stdin. + */ +static char* +GetSubjectFromUser(unsigned long serial) +{ + char buf[STDIN_BUF_SIZE]; + char common_name_buf[STDIN_BUF_SIZE]; + char *common_name, *state, *orgunit, *country, *org, *locality; + char *email, *uid; + char *subject; + char *cp; + int subjectlen=0; + + common_name = state = orgunit = country = org = locality = email = + uid = subject = NULL; + + /* Get subject information */ + PR_fprintf(PR_STDOUT, +"\nEnter certificate information. All fields are optional. Acceptable\n" +"characters are numbers, letters, spaces, and apostrophes.\n"); + +#ifdef VERBOSE_PROMPTS + PR_fprintf(PR_STDOUT, "\nCOMMON NAME\n" +"Enter the full name you want to give your certificate. (Example: Test-Only\n" +"Object Signing Certificate)\n" +"-->"); +#else + PR_fprintf(PR_STDOUT, "certificate common name: "); +#endif + fgets(buf, STDIN_BUF_SIZE, stdin); + cp = chop(buf); + if(*cp == '\0') { + sprintf(common_name_buf, "%s (%lu)", DEFAULT_COMMON_NAME, serial); + cp = common_name_buf; + } + common_name = PORT_ZAlloc(strlen(cp) + 6); + if(!common_name) {out_of_memory();} + sprintf(common_name, "CN=%s, ", cp); + subjectlen += strlen(common_name); + +#ifdef VERBOSE_PROMPTS + PR_fprintf(PR_STDOUT, "\nORGANIZATION NAME\n" +"Enter the name of your organization. For example, this could be the name\n" +"of your company.\n" +"-->"); +#else + PR_fprintf(PR_STDOUT, "organization: "); +#endif + fgets(buf, STDIN_BUF_SIZE, stdin); + cp = chop(buf); + if(*cp != '\0') { + org = PORT_ZAlloc(strlen(cp) + 5); + if(!org) {out_of_memory();} + sprintf(org, "O=%s, ", cp); + subjectlen += strlen(org); + } + +#ifdef VERBOSE_PROMPTS + PR_fprintf(PR_STDOUT, "\nORGANIZATION UNIT\n" +"Enter the name of your organization unit. For example, this could be the\n" +"name of your department.\n" +"-->"); +#else + PR_fprintf(PR_STDOUT, "organization unit: "); +#endif + fgets(buf, STDIN_BUF_SIZE, stdin); + cp = chop(buf); + if(*cp != '\0') { + orgunit = PORT_ZAlloc(strlen(cp)+6); + if(!orgunit) {out_of_memory();} + sprintf(orgunit, "OU=%s, ", cp); + subjectlen += strlen(orgunit); + } + +#ifdef VERBOSE_PROMPTS + PR_fprintf(PR_STDOUT, "\nSTATE\n" +"Enter the name of your state or province.\n" +"-->"); +#else + PR_fprintf(PR_STDOUT, "state or province: "); +#endif + fgets(buf, STDIN_BUF_SIZE, stdin); + cp = chop(buf); + if(*cp != '\0') { + state = PORT_ZAlloc(strlen(cp)+6); + if(!state) {out_of_memory();} + sprintf(state, "ST=%s, ", cp); + subjectlen += strlen(state); + } + +#ifdef VERBOSE_PROMPTS + PR_fprintf(PR_STDOUT, "\nCOUNTRY\n" +"Enter the 2-character abbreviation for the name of your country.\n" +"-->"); +#else + PR_fprintf(PR_STDOUT, "country (must be exactly 2 characters): "); +#endif + fgets(buf, STDIN_BUF_SIZE, stdin); + cp = chop(cp); + if(strlen(cp) != 2) { + *cp = '\0'; /* country code must be 2 chars */ + } + if(*cp != '\0') { + country = PORT_ZAlloc(strlen(cp)+5); + if(!country) {out_of_memory();} + sprintf(country, "C=%s, ", cp); + subjectlen += strlen(country); + } + +#ifdef VERBOSE_PROMPTS + PR_fprintf(PR_STDOUT, "\nUSERNAME\n" +"Enter your system username or UID\n" +"-->"); +#else + PR_fprintf(PR_STDOUT, "username: "); +#endif + fgets(buf, STDIN_BUF_SIZE, stdin); + cp = chop(buf); + if(*cp != '\0') { + uid = PORT_ZAlloc(strlen(cp)+7); + if(!uid) {out_of_memory();} + sprintf(uid, "UID=%s, ", cp); + subjectlen += strlen(uid); + } + +#ifdef VERBOSE_PROMPTS + PR_fprintf(PR_STDOUT, "\nEMAIL ADDRESS\n" +"Enter your email address.\n" +"-->"); +#else + PR_fprintf(PR_STDOUT, "email address: "); +#endif + fgets(buf, STDIN_BUF_SIZE, stdin); + cp = chop(buf); + if(*cp != '\0') { + email = PORT_ZAlloc(strlen(cp)+5); + if(!email) {out_of_memory();} + sprintf(email, "E=%s,", cp); + subjectlen += strlen(email); + } + + subjectlen++; + + subject = PORT_ZAlloc(subjectlen); + if(!subject) {out_of_memory();} + + sprintf(subject, "%s%s%s%s%s%s%s", + common_name ? common_name : "", + org ? org : "", + orgunit ? orgunit : "", + state ? state : "", + country ? country : "", + uid ? uid : "", + email ? email : "" + ); + if( (strlen(subject) > 1) && (subject[strlen(subject)-1] == ' ') ) { + subject[strlen(subject)-2] = '\0'; + } + + PORT_Free(common_name); + PORT_Free(org); + PORT_Free(orgunit); + PORT_Free(state); + PORT_Free(country); + PORT_Free(uid); + PORT_Free(email); + + return subject; +} + +/************************************************************************** + * + * G e n e r a t e S e l f S i g n e d O b j e c t S i g n i n g C e r t + * *phew*^ + * + */ +static CERTCertificate* +GenerateSelfSignedObjectSigningCert(char *nickname, CERTCertDBHandle *db, + char *subject, unsigned long serial, int keysize, char *token) +{ + CERTCertificate *cert, *temp_cert; + SECItem *derCert; + CERTCertificateRequest *req; + + PK11SlotInfo *slot = NULL; + SECKEYPrivateKey *privk = NULL; + SECKEYPublicKey *pubk = NULL; + + if( token ) { + slot = PK11_FindSlotByName(token); + } else { + slot = PK11_GetInternalKeySlot(); + } + + if (slot == NULL) { + PR_fprintf(errorFD, "Can't find PKCS11 slot %s\n", + token ? token : ""); + errorCount++; + exit (ERRX); + } + + if( GenerateKeyPair(slot, &pubk, &privk, keysize) != SECSuccess) { + FatalError("Error generating keypair."); + } + req = make_cert_request (subject, pubk); + temp_cert = make_cert (req, serial, &req->subject); + if(set_cert_type(temp_cert, + NS_CERT_TYPE_OBJECT_SIGNING | NS_CERT_TYPE_OBJECT_SIGNING_CA) + != SECSuccess) { + FatalError("Unable to set cert type"); + } + + derCert = sign_cert (temp_cert, privk); + cert = install_cert(db, derCert, nickname); + if(ChangeTrustAttributes(db, cert, ",,uC") != SECSuccess) { + FatalError("Unable to change trust on generated certificate"); + } + + /* !!! Free memory ? !!! */ + PK11_FreeSlot(slot); + SECKEY_DestroyPrivateKey(privk); + SECKEY_DestroyPublicKey(pubk); + + return cert; +} + +/************************************************************************** + * + * C h a n g e T r u s t A t t r i b u t e s + */ +static SECStatus +ChangeTrustAttributes(CERTCertDBHandle *db, CERTCertificate *cert, char *trusts) +{ + + CERTCertTrust *trust; + + if(!db || !cert || !trusts) { + PR_fprintf(errorFD,"ChangeTrustAttributes got incomplete arguments.\n"); + errorCount++; + return SECFailure; + } + + trust = (CERTCertTrust*) PORT_ZAlloc(sizeof(CERTCertTrust)); + if(!trust) { + PR_fprintf(errorFD, "ChangeTrustAttributes unable to allocate " + "CERTCertTrust\n"); + errorCount++; + return SECFailure; + } + + if( CERT_DecodeTrustString(trust, trusts) ) { + return SECFailure; + } + + if( CERT_ChangeCertTrust(db, cert, trust) ) { + PR_fprintf(errorFD, "unable to modify trust attributes for cert %s\n", + cert->nickname ? cert->nickname : ""); + errorCount++; + return SECFailure; + } + + return SECSuccess; +} + +/************************************************************************* + * + * s e t _ c e r t _ t y p e + */ +static SECStatus +set_cert_type(CERTCertificate *cert, unsigned int type) +{ + void *context; + SECStatus status = SECSuccess; + SECItem certType; + char ctype; + + context = CERT_StartCertExtensions(cert); + + certType.type = siBuffer; + certType.data = (unsigned char*) &ctype; + certType.len = 1; + ctype = (unsigned char)type; + if(CERT_EncodeAndAddBitStrExtension(context, SEC_OID_NS_CERT_EXT_CERT_TYPE, + &certType, PR_TRUE /*critical*/) != SECSuccess) { + status = SECFailure; + } + + if(CERT_FinishExtensions(context) != SECSuccess) { + status = SECFailure; + } + + return status; +} + +/******************************************************************** + * + * s i g n _ c e r t + */ +static SECItem * +sign_cert(CERTCertificate *cert, SECKEYPrivateKey *privk) +{ + SECStatus rv; + + SECItem der2; + SECItem *result2; + + void *dummy; + SECOidTag alg = SEC_OID_UNKNOWN; + + switch (privk->keyType) + { + case rsaKey: + alg = SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION; + break; + + case dsaKey: + alg = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; + break; + default: + FatalError("Unknown key type"); + } + PORT_Assert(alg != SEC_OID_UNKNOWN); + + rv = SECOID_SetAlgorithmID (cert->arena, &cert->signature, alg, 0); + + if (rv != SECSuccess) + { + PR_fprintf(errorFD, "%s: unable to set signature alg id\n", PROGRAM_NAME); + errorCount++; + exit (ERRX); + } + + der2.len = 0; + der2.data = NULL; + + dummy = SEC_ASN1EncodeItem + (cert->arena, &der2, cert, CERT_CertificateTemplate); + + if (rv != SECSuccess) + { + PR_fprintf(errorFD, "%s: error encoding cert\n", PROGRAM_NAME); + errorCount++; + exit (ERRX); + } + + result2 = (SECItem *) PORT_ArenaZAlloc (cert->arena, sizeof (SECItem)); + if (result2 == NULL) + out_of_memory(); + + rv = SEC_DerSignData + (cert->arena, result2, der2.data, der2.len, privk, alg); + + if (rv != SECSuccess) + { + PR_fprintf(errorFD, "can't sign encoded certificate data\n"); + errorCount++; + exit (ERRX); + } + else if(verbosity >= 0) { + PR_fprintf(outputFD, "certificate has been signed\n"); + } + + cert->derCert = *result2; + + return result2; +} + +/********************************************************************* + * + * i n s t a l l _ c e r t + * + * Installs the cert in the permanent database. + */ +static CERTCertificate* +install_cert(CERTCertDBHandle *db, SECItem *derCert, char *nickname) +{ + CERTCertificate *newcert; + PK11SlotInfo *newSlot; + + newcert = CERT_DecodeDERCertificate(derCert, PR_TRUE, NULL); + + if (newcert == NULL) { + PR_fprintf(errorFD, "%s: can't create new certificate\n", PROGRAM_NAME); + errorCount++; + exit (ERRX); + } + + newSlot = PK11_ImportCertForKey(newcert, nickname, NULL /*wincx*/); + if( newSlot == NULL ) { + PR_fprintf(errorFD, "Unable to install certificate\n"); + errorCount++; + exit(ERRX); + } + PK11_FreeSlot(newSlot); + + if(verbosity >= 0){ + PR_fprintf(outputFD, "certificate \"%s\" added to database\n", nickname); + } + + return newcert; +} + +/****************************************************************** + * + * G e n e r a t e K e y P a i r + */ +static SECStatus +GenerateKeyPair(PK11SlotInfo *slot, SECKEYPublicKey **pubk, + SECKEYPrivateKey **privk, int keysize) +{ + + PK11RSAGenParams rsaParams; + + if( keysize == -1 ) { + rsaParams.keySizeInBits = DEFAULT_RSA_KEY_SIZE; + } else { + rsaParams.keySizeInBits = keysize; + } + rsaParams.pe = 0x10001; + + if(PK11_Authenticate( slot, PR_FALSE /*loadCerts*/, NULL /*wincx*/) + != SECSuccess) { + SECU_PrintError(progName, "failure authenticating to key database.\n"); + exit(ERRX); + } + + *privk = PK11_GenerateKeyPair (slot, CKM_RSA_PKCS_KEY_PAIR_GEN, &rsaParams, + pubk, PR_TRUE /*isPerm*/, PR_TRUE /*isSensitive*/, NULL /*wincx*/ ); + + if (*privk != NULL && *pubk != NULL) { + if(verbosity >= 0) { + PR_fprintf(outputFD, "generated public/private key pair\n"); + } + } else { + SECU_PrintError(progName, "failure generating key pair\n"); + exit (ERRX); + } + + return SECSuccess; +} + +/****************************************************************** + * + * m a k e _ c e r t _ r e q u e s t + */ +static CERTCertificateRequest* +make_cert_request(char *subject, SECKEYPublicKey *pubk) +{ + CERTName *subj; + CERTSubjectPublicKeyInfo *spki; + + CERTCertificateRequest *req; + + /* Create info about public key */ + spki = SECKEY_CreateSubjectPublicKeyInfo(pubk); + if (!spki) { + SECU_PrintError(progName, "unable to create subject public key"); + exit (ERRX); + } + + subj = CERT_AsciiToName (subject); + if(subj == NULL) { + FatalError("Invalid data in certificate description"); + } + + /* Generate certificate request */ + req = CERT_CreateCertificateRequest(subj, spki, 0); + if (!req) { + SECU_PrintError(progName, "unable to make certificate request"); + exit (ERRX); + } + + if(verbosity >= 0) { + PR_fprintf(outputFD, "certificate request generated\n"); + } + + return req; +} + +/****************************************************************** + * + * m a k e _ c e r t + */ +static CERTCertificate * +make_cert(CERTCertificateRequest *req, unsigned long serial, + CERTName *ca_subject) +{ + CERTCertificate *cert; + + CERTValidity *validity = NULL; + + PRTime now, after; + PRExplodedTime printableTime; + + now = PR_Now(); + PR_ExplodeTime (now, PR_GMTParameters, &printableTime); + + printableTime.tm_month += 3; + after = PR_ImplodeTime (&printableTime); + + validity = CERT_CreateValidity (now, after); + + if (validity == NULL) + { + PR_fprintf(errorFD, "%s: error creating certificate validity\n", PROGRAM_NAME); + errorCount++; + exit (ERRX); + } + + cert = CERT_CreateCertificate + (serial, ca_subject, validity, req); + + if (cert == NULL) + { + /* should probably be more precise here */ + PR_fprintf(errorFD, "%s: error while generating certificate\n", PROGRAM_NAME); + errorCount++; + exit (ERRX); + } + + return cert; + } + +/************************************************************************* + * + * o u t p u t _ c a _ c e r t + */ +static void +output_ca_cert (CERTCertificate *cert, CERTCertDBHandle *db) + { + FILE *out; + + SECItem *encodedCertChain; + SEC_PKCS7ContentInfo *certChain; + char *filename; + + /* the raw */ + + filename = PORT_ZAlloc(strlen(DEFAULT_X509_BASENAME)+8); + if(!filename) out_of_memory(); + + sprintf(filename, "%s.raw", DEFAULT_X509_BASENAME); + if ((out = fopen (filename, "wb")) == NULL) + { + PR_fprintf(errorFD, "%s: Can't open %s output file\n", PROGRAM_NAME, filename); + errorCount++; + exit(ERRX); + } + + certChain = SEC_PKCS7CreateCertsOnly (cert, PR_TRUE, db); + encodedCertChain + = SEC_PKCS7EncodeItem (NULL, NULL, certChain, NULL, NULL, NULL); + SEC_PKCS7DestroyContentInfo (certChain); + + if (encodedCertChain) + { + fprintf(out, "Content-type: application/x-x509-ca-cert\n\n"); + fwrite (encodedCertChain->data, 1, encodedCertChain->len, out); + SECITEM_FreeItem(encodedCertChain, PR_TRUE); + } + else { + PR_fprintf(errorFD, "%s: Can't DER encode this certificate\n", PROGRAM_NAME); + errorCount++; + exit(ERRX); + } + + fclose (out); + + /* and the cooked */ + + sprintf(filename, "%s.cacert", DEFAULT_X509_BASENAME); + if ((out = fopen (filename, "wb")) == NULL) + { + PR_fprintf(errorFD, "%s: Can't open %s output file\n", PROGRAM_NAME, filename); + errorCount++; + return; + } + + fprintf (out, "%s\n%s\n%s\n", + NS_CERT_HEADER, + BTOA_DataToAscii (cert->derCert.data, cert->derCert.len), + NS_CERT_TRAILER); + + fclose (out); + + if(verbosity >= 0) { + PR_fprintf(outputFD, "Exported certificate to %s.raw and %s.cacert.\n", + DEFAULT_X509_BASENAME, DEFAULT_X509_BASENAME); + } +} diff --git a/security/nss/cmd/signtool/javascript.c b/security/nss/cmd/signtool/javascript.c new file mode 100644 index 000000000..142a9751a --- /dev/null +++ b/security/nss/cmd/signtool/javascript.c @@ -0,0 +1,1790 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "signtool.h" +#include <prmem.h> +#include <prio.h> +#include <prenv.h> + +static int javascript_fn(char *relpath, char *basedir, char *reldir, + char *filename, void *arg); +static int extract_js (char *filename); +static int copyinto (char *from, char *to); +static PRStatus ensureExists (char *base, char *path); +static int make_dirs(char *path, PRInt32 file_perms); + +static char *jartree = NULL; +static int idOrdinal; +static PRBool dumpParse=PR_FALSE; + +static char *event_handlers[] = { +"onAbort", +"onBlur", +"onChange", +"onClick", +"onDblClick", +"onDragDrop", +"onError", +"onFocus", +"onKeyDown", +"onKeyPress", +"onKeyUp", +"onLoad", +"onMouseDown", +"onMouseMove", +"onMouseOut", +"onMouseOver", +"onMouseUp", +"onMove", +"onReset", +"onResize", +"onSelect", +"onSubmit", +"onUnload" +}; +static int num_handlers = 23; + +/* + * I n l i n e J a v a S c r i p t + * + * Javascript signing. Instead of passing an archive to signtool, + * a directory containing html files is given. Archives are created + * from the archive= and src= tag attributes inside the html, + * as appropriate. Then the archives are signed. + * + */ +int +InlineJavaScript(char *dir, PRBool recurse) +{ + jartree = dir; + if(verbosity >= 0) { + PR_fprintf(outputFD, "\nGenerating inline signatures from HTML files in: %s\n", dir); + } + if(PR_GetEnv("SIGNTOOL_DUMP_PARSE")) { + dumpParse = PR_TRUE; + } + + return foreach(dir, "", javascript_fn, recurse, PR_FALSE /*include dirs*/, + (void*)NULL); + +} + +/************************************************************************ + * + * j a v a s c r i p t _ f n + */ +static int javascript_fn + (char *relpath, char *basedir, char *reldir, char *filename, void *arg) +{ + char fullname [FNSIZE]; + + /* only process inline scripts from .htm, .html, and .shtml*/ + + if(! (PL_strcaserstr(filename, ".htm") == filename + strlen(filename) -4) && + ! (PL_strcaserstr(filename, ".html") == filename + strlen(filename) -5)&& + ! (PL_strcaserstr(filename, ".shtml") == filename + strlen(filename)-6)){ + return 0; + } + + /* don't process scripts that signtool has already + extracted (those that are inside .arc directories) */ + + if(PL_strcaserstr(filename, ".arc") == filename + strlen(filename) - 4) + return 0; + + if(verbosity >= 0) { + PR_fprintf(outputFD, "Processing HTML file: %s\n", relpath); + } + + /* reset firstArchive at top of each HTML file */ + + /* skip directories that contain extracted scripts */ + + if(PL_strcaserstr(reldir, ".arc") == reldir + strlen(reldir) - 4) + return 0; + + sprintf (fullname, "%s/%s", basedir, relpath); + return extract_js (fullname); +} + +/*=========================================================================== + = + = D A T A S T R U C T U R E S + = +*/ +typedef enum { + TEXT_HTML_STATE=0, + SCRIPT_HTML_STATE +} HTML_STATE ; + +typedef enum { + /* we start in the start state */ + START_STATE, + + /* We are looking for or reading in an attribute */ + GET_ATT_STATE, + + /* We're burning ws before finding an attribute */ + PRE_ATT_WS_STATE, + + /* We're burning ws after an attribute. Looking for an '='. */ + POST_ATT_WS_STATE, + + /* We're burning ws after an '=', waiting for a value */ + PRE_VAL_WS_STATE, + + /* We're reading in a value */ + GET_VALUE_STATE, + + /* We're reading in a value that's inside quotes */ + GET_QUOTED_VAL_STATE, + + /* We've encountered the closing '>' */ + DONE_STATE, + + /* Error state */ + ERR_STATE +} TAG_STATE ; + +typedef struct AVPair_Str { + char *attribute; + char *value; + unsigned int valueLine; /* the line that the value ends on */ + struct AVPair_Str *next; +} AVPair; + +typedef enum { + APPLET_TAG, + SCRIPT_TAG, + LINK_TAG, + STYLE_TAG, + COMMENT_TAG, + OTHER_TAG +} TAG_TYPE ; + +typedef struct { + TAG_TYPE type; + AVPair *attList; + AVPair *attListTail; + char *text; +} TagItem; + +typedef enum { + TAG_ITEM, + TEXT_ITEM +} ITEM_TYPE ; + +typedef struct HTMLItem_Str{ + unsigned int startLine; + unsigned int endLine; + ITEM_TYPE type; + union { + TagItem *tag; + char *text; + } item; + struct HTMLItem_Str *next; +} HTMLItem; + +typedef struct { + PRFileDesc *fd; + PRInt32 curIndex; + PRBool IsEOF; +#define FILE_BUFFER_BUFSIZE 512 + char buf[FILE_BUFFER_BUFSIZE]; + PRInt32 startOffset; + PRInt32 maxIndex; + unsigned int lineNum; +} FileBuffer; + +/*=========================================================================== + = + = F U N C T I O N S + = +*/ +static HTMLItem* CreateTextItem(char *text, unsigned int startline, + unsigned int endline); +static HTMLItem* CreateTagItem(TagItem* ti, unsigned int startline, + unsigned int endline); +static TagItem* ProcessTag(FileBuffer* fb, char **errStr); +static void DestroyHTMLItem(HTMLItem *item); +static void DestroyTagItem(TagItem* ti); +static TAG_TYPE GetTagType(char *att); +static FileBuffer* FB_Create(PRFileDesc* fd); +static int FB_GetChar(FileBuffer *fb); +static PRInt32 FB_GetPointer(FileBuffer *fb); +static PRInt32 FB_GetRange(FileBuffer *fb, PRInt32 start, PRInt32 end, + char **buf); +static unsigned int FB_GetLineNum(FileBuffer *fb); +static void FB_Destroy(FileBuffer *fb); +static void PrintTagItem(PRFileDesc *fd, TagItem *ti); +static void PrintHTMLStream(PRFileDesc *fd, HTMLItem *head); + +/************************************************************************ + * + * C r e a t e T e x t I t e m + */ +static HTMLItem* +CreateTextItem(char *text, unsigned int startline, unsigned int endline) +{ + HTMLItem *item; + + item = PR_Malloc(sizeof(HTMLItem)); + if(!item) { + return NULL; + } + + item->type = TEXT_ITEM; + item->item.text = text; + item->next = NULL; + item->startLine = startline; + item->endLine = endline; + + return item; +} + +/************************************************************************ + * + * C r e a t e T a g I t e m + */ +static HTMLItem* +CreateTagItem(TagItem* ti, unsigned int startline, unsigned int endline) +{ + HTMLItem *item; + + item = PR_Malloc(sizeof(HTMLItem)); + if(!item) { + return NULL; + } + + item->type = TAG_ITEM; + item->item.tag = ti; + item->next = NULL; + item->startLine = startline; + item->endLine = endline; + + return item; +} + +static PRBool +isAttChar(char c) +{ + return (isalnum(c) || c=='/' || c=='-'); +} + +/************************************************************************ + * + * P r o c e s s T a g + */ +static TagItem* +ProcessTag(FileBuffer* fb, char **errStr) +{ + TAG_STATE state; + PRInt32 startText, startID, curPos; + PRBool firstAtt; + int curchar; + TagItem *ti=NULL; + AVPair *curPair=NULL; + char quotechar='\0'; + unsigned int linenum; + unsigned int startline; + + state = START_STATE; + + startID = FB_GetPointer(fb); + startText = startID; + firstAtt = PR_TRUE; + + ti = (TagItem*) PR_Malloc(sizeof(TagItem)); + if(!ti) out_of_memory(); + ti->type = OTHER_TAG; + ti->attList = NULL; + ti->attListTail = NULL; + ti->text = NULL; + + startline = FB_GetLineNum(fb); + + while(state != DONE_STATE && state != ERR_STATE) { + linenum = FB_GetLineNum(fb); + curchar = FB_GetChar(fb); + if(curchar == EOF) { + *errStr = PR_smprintf( + "line %d: Unexpected end-of-file while parsing tag starting at line %d.\n", linenum, startline); + state = ERR_STATE; + continue; + } + + switch(state) { + case START_STATE: + if(curchar=='!') { + /* + * SGML tag or comment + * Here's the general rule for SGML tags. Everything from + * <! to > is the tag. Inside the tag, comments are + * delimited with --. So we are looking for the first '>' + * that is not commented out, that is, not inside a pair + * of --: <!DOCTYPE --this is a comment >(psyche!) --> + */ + + PRBool inComment = PR_FALSE; + short hyphenCount = 0; /* number of consecutive hyphens */ + + while(1) { + linenum = FB_GetLineNum(fb); + curchar = FB_GetChar(fb); + if(curchar == EOF) { + /* Uh oh, EOF inside comment */ + *errStr = PR_smprintf( + "line %d: Unexpected end-of-file inside comment starting at line %d.\n", + linenum, startline); + state = ERR_STATE; + break; + } + if(curchar=='-') { + if(hyphenCount==1) { + /* This is a comment delimiter */ + inComment = !inComment; + hyphenCount=0; + } else { + /* beginning of a comment delimiter? */ + hyphenCount=1; + } + } else if(curchar=='>') { + if(!inComment) { + /* This is the end of the tag */ + state = DONE_STATE; + break; + } else { + /* The > is inside a comment, so it's not + * really the end of the tag */ + hyphenCount=0; + } + } else { + hyphenCount = 0; + } + } + ti->type = COMMENT_TAG; + break; + } + /* fall through */ + case GET_ATT_STATE: + if(isspace(curchar) || curchar=='=' || curchar=='>') { + /* end of the current attribute */ + curPos = FB_GetPointer(fb)-2; + if(curPos >= startID) { + /* We have an attribute */ + curPair = (AVPair*)PR_Malloc(sizeof(AVPair)); + if(!curPair) out_of_memory(); + curPair->value = NULL; + curPair->next = NULL; + FB_GetRange(fb, startID, curPos, &curPair->attribute); + + /* Stick this attribute on the list */ + if(ti->attListTail) { + ti->attListTail->next = curPair; + ti->attListTail = curPair; + } else { + ti->attList = ti->attListTail = curPair; + } + + /* If this is the first attribute, find the type of tag + * based on it. Also, start saving the text of the tag. */ + if(firstAtt) { + ti->type = GetTagType(curPair->attribute); + startText = FB_GetPointer(fb)-1; + firstAtt = PR_FALSE; + } + } else { + if(curchar=='=') { + /* If we don't have any attribute but we do have an + * equal sign, that's an error */ + *errStr = PR_smprintf("line %d: Malformed tag starting at line %d.\n", linenum, startline); + state = ERR_STATE; + break; + } + } + + /* Compute next state */ + if(curchar=='=') { + startID = FB_GetPointer(fb); + state = PRE_VAL_WS_STATE; + } else if(curchar=='>') { + state = DONE_STATE; + } else if(curPair) { + state = POST_ATT_WS_STATE; + } else { + state = PRE_ATT_WS_STATE; + } + } else if(isAttChar(curchar)) { + /* Just another char in the attribute. Do nothing */ + state = GET_ATT_STATE; + } else { + /* bogus char */ + *errStr= PR_smprintf("line %d: Bogus chararacter '%c' in tag.\n", + linenum, curchar); + state = ERR_STATE; + break; + } + break; + case PRE_ATT_WS_STATE: + if(curchar=='>') { + state = DONE_STATE; + } else if(isspace(curchar)) { + /* more whitespace, do nothing */ + } else if(isAttChar(curchar)) { + /* starting another attribute */ + startID = FB_GetPointer(fb)-1; + state = GET_ATT_STATE; + } else { + /* bogus char */ + *errStr = PR_smprintf("line %d: Bogus character '%c' in tag.\n", + linenum, curchar); + state = ERR_STATE; + break; + } + break; + case POST_ATT_WS_STATE: + if(curchar=='>') { + state = DONE_STATE; + } else if(isspace(curchar)) { + /* more whitespace, do nothing */ + } else if(isAttChar(curchar)) { + /* starting another attribute */ + startID = FB_GetPointer(fb)-1; + state = GET_ATT_STATE; + } else if(curchar=='=') { + /* there was whitespace between the attribute and its equal + * sign, which means there's a value coming up */ + state = PRE_VAL_WS_STATE; + } else { + /* bogus char */ + *errStr = PR_smprintf("line %d: Bogus character '%c' in tag.\n", + linenum, curchar); + state = ERR_STATE; + break; + } + break; + case PRE_VAL_WS_STATE: + if(curchar=='>') { + /* premature end-of-tag (sounds like a personal problem). */ + *errStr = PR_smprintf( + "line %d: End of tag while waiting for value.\n", linenum); + state = ERR_STATE; + break; + } else if(isspace(curchar)) { + /* more whitespace, do nothing */ + break; + } else { + /* this must be some sort of value. Fall through + * to GET_VALUE_STATE */ + startID=FB_GetPointer(fb)-1; + state = GET_VALUE_STATE; + } + /* Fall through if we didn't break on '>' or whitespace */ + case GET_VALUE_STATE: + if(isspace(curchar) || curchar=='>') { + /* end of value */ + curPos = FB_GetPointer(fb)-2; + if(curPos >= startID) { + /* Grab the value */ + FB_GetRange(fb, startID, curPos, &curPair->value); + curPair->valueLine = linenum; + } else { + /* empty value, leave as NULL */ + } + if(isspace(curchar)) { + state = PRE_ATT_WS_STATE; + } else { + state = DONE_STATE; + } + } else if(curchar=='\"' || curchar=='\'') { + /* quoted value. Start recording the value inside the quote*/ + startID = FB_GetPointer(fb); + state = GET_QUOTED_VAL_STATE; + PORT_Assert(quotechar == '\0'); + quotechar = curchar; /* look for matching quote type */ + } else { + /* just more value */ + } + break; + case GET_QUOTED_VAL_STATE: + PORT_Assert(quotechar != '\0'); + if(curchar == quotechar) { + /* end of quoted value */ + curPos = FB_GetPointer(fb)-2; + if(curPos >= startID) { + /* Grab the value */ + FB_GetRange(fb, startID, curPos, &curPair->value); + curPair->valueLine = linenum; + } else { + /* empty value, leave it as NULL */ + } + state = GET_ATT_STATE; + quotechar = '\0'; + startID = FB_GetPointer(fb); + } else { + /* more quoted value, continue */ + } + break; + case DONE_STATE: + case ERR_STATE: + default: + ; /* should never get here */ + } + } + + if(state == DONE_STATE) { + /* Get the text of the tag */ + curPos = FB_GetPointer(fb)-1; + FB_GetRange(fb, startText, curPos, &ti->text); + + /* Return the tag */ + return ti; + } + + /* Uh oh, an error. Kill the tag item*/ + DestroyTagItem(ti); + return NULL; +} + +/************************************************************************ + * + * D e s t r o y H T M L I t e m + */ +static void +DestroyHTMLItem(HTMLItem *item) +{ + if(item->type == TAG_ITEM) { + DestroyTagItem(item->item.tag); + } else { + if(item->item.text) { + PR_Free(item->item.text); + } + } +} + +/************************************************************************ + * + * D e s t r o y T a g I t e m + */ +static void +DestroyTagItem(TagItem* ti) +{ + AVPair *temp; + + if(ti->text) { + PR_Free(ti->text); ti->text = NULL; + } + + while(ti->attList) { + temp = ti->attList; + ti->attList = ti->attList->next; + + if(temp->attribute) { + PR_Free(temp->attribute); temp->attribute = NULL; + } + if(temp->value) { + PR_Free(temp->value); temp->value = NULL; + } + PR_Free(temp); + } + + PR_Free(ti); +} + +/************************************************************************ + * + * G e t T a g T y p e + */ +static TAG_TYPE +GetTagType(char *att) +{ + if(!PORT_Strcasecmp(att, "APPLET")) { + return APPLET_TAG; + } + if(!PORT_Strcasecmp(att, "SCRIPT")) { + return SCRIPT_TAG; + } + if(!PORT_Strcasecmp(att, "LINK")) { + return LINK_TAG; + } + if(!PORT_Strcasecmp(att, "STYLE")) { + return STYLE_TAG; + } + return OTHER_TAG; +} + +/************************************************************************ + * + * F B _ C r e a t e + */ +static FileBuffer* +FB_Create(PRFileDesc* fd) +{ + FileBuffer *fb; + PRInt32 amountRead; + PRInt32 storedOffset; + + fb = (FileBuffer*) PR_Malloc(sizeof(FileBuffer)); + fb->fd = fd; + storedOffset = PR_Seek(fd, 0, PR_SEEK_CUR); + PR_Seek(fd, 0, PR_SEEK_SET); + fb->startOffset = 0; + amountRead = PR_Read(fd, fb->buf, FILE_BUFFER_BUFSIZE); + if(amountRead == -1) goto loser; + fb->maxIndex = amountRead-1; + fb->curIndex = 0; + fb->IsEOF = (fb->curIndex>fb->maxIndex) ? PR_TRUE : PR_FALSE; + fb->lineNum = 1; + + PR_Seek(fd, storedOffset, PR_SEEK_SET); + return fb; +loser: + PR_Seek(fd, storedOffset, PR_SEEK_SET); + PR_Free(fb); + return NULL; +} + +/************************************************************************ + * + * F B _ G e t C h a r + */ +static int +FB_GetChar(FileBuffer *fb) +{ + PRInt32 storedOffset; + PRInt32 amountRead; + int retval=-1; + + if(fb->IsEOF) { + return EOF; + } + + storedOffset = PR_Seek(fb->fd, 0, PR_SEEK_CUR); + + retval = fb->buf[fb->curIndex++]; + if(retval=='\n') fb->lineNum++; + + if(fb->curIndex > fb->maxIndex) { + /* We're at the end of the buffer. Try to get some new data from the + * file */ + fb->startOffset += fb->maxIndex+1; + PR_Seek(fb->fd, fb->startOffset, PR_SEEK_SET); + amountRead = PR_Read(fb->fd, fb->buf, FILE_BUFFER_BUFSIZE); + if(amountRead==-1) goto loser; + fb->maxIndex = amountRead-1; + fb->curIndex = 0; + } + + fb->IsEOF = (fb->curIndex > fb->maxIndex) ? PR_TRUE : PR_FALSE; + +loser: + PR_Seek(fb->fd, storedOffset, PR_SEEK_SET); + return retval; +} + +/************************************************************************ + * + * F B _ G e t L i n e N u m + * + */ +static unsigned int +FB_GetLineNum(FileBuffer *fb) +{ + return fb->lineNum; +} + +/************************************************************************ + * + * F B _ G e t P o i n t e r + * + */ +static PRInt32 +FB_GetPointer(FileBuffer *fb) +{ + return fb->startOffset + fb->curIndex; +} + +/************************************************************************ + * + * F B _ G e t R a n g e + * + */ +static PRInt32 +FB_GetRange(FileBuffer *fb, PRInt32 start, PRInt32 end, char **buf) +{ + PRInt32 amountRead; + PRInt32 storedOffset; + + *buf = PR_Malloc(end-start+2); + if(*buf == NULL) { + return 0; + } + + storedOffset = PR_Seek(fb->fd, 0, PR_SEEK_CUR); + PR_Seek(fb->fd, start, PR_SEEK_SET); + amountRead = PR_Read(fb->fd, *buf, end-start+1); + PR_Seek(fb->fd, storedOffset, PR_SEEK_SET); + if(amountRead == -1) { + PR_Free(*buf); + *buf = NULL; + return 0; + } + + (*buf)[end-start+1] = '\0'; + return amountRead; +} + + +/************************************************************************ + * + * F B _ D e s t r o y + * + */ +static void +FB_Destroy(FileBuffer *fb) +{ + if(fb) { + PR_Free(fb); + } +} + +/************************************************************************ + * + * P r i n t T a g I t e m + * + */ +static void +PrintTagItem(PRFileDesc *fd, TagItem *ti) +{ + AVPair *pair; + + PR_fprintf(fd, "TAG:\n----\nType: "); + switch(ti->type) { + case APPLET_TAG: + PR_fprintf(fd, "applet\n"); + break; + case SCRIPT_TAG: + PR_fprintf(fd, "script\n"); + break; + case LINK_TAG: + PR_fprintf(fd, "link\n"); + break; + case STYLE_TAG: + PR_fprintf(fd, "style\n"); + break; + case COMMENT_TAG: + PR_fprintf(fd, "comment\n"); + break; + case OTHER_TAG: + default: + PR_fprintf(fd, "other\n"); + break; + } + + PR_fprintf(fd, "Attributes:\n"); + for(pair = ti->attList; pair; pair=pair->next) { + PR_fprintf(fd, "\t%s=%s\n", pair->attribute, + pair->value ? pair->value : ""); + } + PR_fprintf(fd, "Text:%s\n", ti->text ? ti->text : ""); + + PR_fprintf(fd, "---End of tag---\n"); +} + + +/************************************************************************ + * + * P r i n t H T M L S t r e a m + * + */ +static void +PrintHTMLStream(PRFileDesc *fd, HTMLItem *head) +{ + while(head) { + if(head->type==TAG_ITEM) { + PrintTagItem(fd, head->item.tag); + } else { + PR_fprintf(fd, "\nTEXT:\n-----\n%s\n-----\n\n", head->item.text); + } + head = head->next; + } +} + +/************************************************************************ + * + * S a v e I n l i n e S c r i p t + * + */ +static int +SaveInlineScript(char *text, char *id, char *basedir, char *archiveDir) +{ + char *filename=NULL; + PRFileDesc *fd=NULL; + int retval = -1; + PRInt32 writeLen; + char *ilDir=NULL; + + if(!text || !id || !archiveDir) { + return -1; + } + + if(dumpParse) { + PR_fprintf(outputFD, "SaveInlineScript: text=%s, id=%s, \n" + "basedir=%s, archiveDir=%s\n", + text, id, basedir, archiveDir); + } + + /* Make sure the archive directory is around */ + if(ensureExists(basedir, archiveDir) != PR_SUCCESS) { + PR_fprintf(errorFD, + "ERROR: Unable to create archive directory %s.\n", archiveDir); + errorCount++; + return -1; + } + + /* Make sure the inline script directory is around */ + ilDir = PR_smprintf("%s/inlineScripts", archiveDir); + scriptdir = "inlineScripts"; + if(ensureExists(basedir, ilDir) != PR_SUCCESS) { + PR_fprintf(errorFD, + "ERROR: Unable to create directory %s.\n", ilDir); + errorCount++; + return -1; + } + + filename = PR_smprintf("%s/%s/%s", basedir, ilDir, id); + + /* If the file already exists, give a warning, then blow it away */ + if(PR_Access(filename, PR_ACCESS_EXISTS) == PR_SUCCESS) { + PR_fprintf(errorFD, + "warning: file \"%s\" already exists--will overwrite.\n", + filename); + warningCount++; + if(rm_dash_r(filename)) { + PR_fprintf(errorFD, + "ERROR: Unable to delete %s.\n", filename); + errorCount++; + goto finish; + } + } + + /* Write text into file with name id */ + fd = PR_Open(filename, PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 0777); + if(!fd) { + PR_fprintf(errorFD, "ERROR: Unable to create file \"%s\".\n", + filename); + errorCount++; + goto finish; + } + writeLen = strlen(text); + if( PR_Write(fd, text, writeLen) != writeLen) { + PR_fprintf(errorFD, "ERROR: Unable to write to file \"%s\".\n", + filename); + errorCount++; + goto finish; + } + + retval = 0; +finish: + if(filename) { + PR_smprintf_free(filename); + } + if(ilDir) { + PR_smprintf_free(ilDir); + } + if(fd) { + PR_Close(fd); + } + return retval; +} + +/************************************************************************ + * + * S a v e U n n a m a b l e S c r i p t + * + */ +static int +SaveUnnamableScript(char *text, char *basedir, char *archiveDir, + char *HTMLfilename) +{ + char *id=NULL; + char *ext=NULL; + char *start=NULL; + int retval = -1; + + if(!text || !archiveDir || !HTMLfilename) { + return -1; + } + + if(dumpParse) { + PR_fprintf(outputFD, "SaveUnnamableScript: text=%s, basedir=%s,\n" + "archiveDir=%s, filename=%s\n", text, basedir, archiveDir, + HTMLfilename); + } + + /* Construct the filename */ + ext = PL_strrchr(HTMLfilename, '.'); + if(ext) { + *ext = '\0'; + } + for(start=HTMLfilename; strpbrk(start, "/\\"); + start=strpbrk(start, "/\\")+1); + if(*start=='\0') start = HTMLfilename; + id = PR_smprintf("_%s%d", start, idOrdinal++); + if(ext) { + *ext = '.'; + } + + /* Now call SaveInlineScript to do the work */ + retval = SaveInlineScript(text, id, basedir, archiveDir); + + PR_Free(id); + + return retval; +} + +/************************************************************************ + * + * S a v e S o u r c e + * + */ +static int +SaveSource(char *src, char *codebase, char *basedir, char *archiveDir) +{ + char *from=NULL, *to=NULL; + int retval = -1; + char *arcDir=NULL; + + if(!src || !archiveDir) { + return -1; + } + + if(dumpParse) { + PR_fprintf(outputFD, "SaveSource: src=%s, codebase=%s, basedir=%s,\n" + "archiveDir=%s\n", src, codebase, basedir, archiveDir); + } + + if(codebase) { + arcDir = PR_smprintf("%s/%s/%s/", basedir, codebase, archiveDir); + } else { + arcDir = PR_smprintf("%s/%s/", basedir, archiveDir); + } + + if(codebase) { + from = PR_smprintf("%s/%s/%s", basedir, codebase, src); + to = PR_smprintf("%s%s", arcDir, src); + } else { + from = PR_smprintf("%s/%s", basedir, src); + to = PR_smprintf("%s%s", arcDir, src); + } + + if(make_dirs(to, 0777)) { + PR_fprintf(errorFD, + "ERROR: Unable to create archive directory %s.\n", archiveDir); + errorCount++; + goto finish; + } + + retval = copyinto(from, to); +finish: + if(from) PR_Free(from); + if(to) PR_Free(to); + if(arcDir) PR_Free(arcDir); + return retval; +} + +/************************************************************************ + * + * T a g T y p e T o S t r i n g + * + */ +char * +TagTypeToString(TAG_TYPE type) +{ + switch(type) { + case APPLET_TAG: + return "APPLET"; + case SCRIPT_TAG: + return "SCRIPT"; + case LINK_TAG: + return "LINK"; + case STYLE_TAG: + return "STYLE"; + default: + break; + } + return "unknown"; +} + +/************************************************************************ + * + * e x t r a c t _ j s + * + */ +static int +extract_js(char *filename) +{ + PRFileDesc *fd=NULL; + FileBuffer *fb=NULL; + HTML_STATE state; + int curchar; + HTMLItem *head = NULL; + HTMLItem *tail = NULL; + PRInt32 textStart; + PRInt32 curOffset; + TagItem *tagp=NULL; + char *text=NULL; + HTMLItem *curitem=NULL; + int retval = -1; + char *tagerr=NULL; + unsigned int linenum, startLine; + char *archiveDir=NULL, *firstArchiveDir=NULL; + HTMLItem *styleList, *styleListTail; + HTMLItem *entityList, *entityListTail; + char *basedir=NULL; + + styleList = entityList = styleListTail = entityListTail = NULL; + + /* Initialize the implicit ID counter for each file */ + idOrdinal = 0; + + /* + * First, parse the HTML into a stream of tags and text. + */ + + fd = PR_Open(filename, PR_RDONLY, 0); + if(!fd) { + PR_fprintf(errorFD, "Unable to open %s for reading.\n", filename); + errorCount++; + return -1; + } + + /* Construct base directory of filename. */ + { + char *cp; + + basedir = PL_strdup(filename); + + /* Remove trailing slashes */ + while( (cp = PL_strprbrk(basedir, "/\\")) == + (basedir + strlen(basedir) - 1)) { + *cp = '\0'; + } + + /* Now remove everything from the last slash (which will be followed + * by a filename) to the end */ + cp = PL_strprbrk(basedir, "/\\"); + if(cp) { + *cp = '\0'; + } + } + + state = TEXT_HTML_STATE; + + fb = FB_Create(fd); + + textStart=0; + startLine = 0; + while(linenum=FB_GetLineNum(fb), (curchar = FB_GetChar(fb)) != EOF) { + switch(state) { + case TEXT_HTML_STATE: + if(curchar == '<') { + /* + * Found a tag + */ + /* Save the text so far to a new text item */ + curOffset = FB_GetPointer(fb)-2; + if(curOffset >= textStart) { + if(FB_GetRange(fb, textStart, curOffset, &text) != + curOffset-textStart+1) { + PR_fprintf(errorFD, + "Unable to read from %s.\n", filename); + errorCount++; + goto loser; + } + /* little fudge here. If the first character on a line + * is '<', meaning a new tag, the preceding text item + * actually ends on the previous line. In this case + * we will be saying that the text segment ends on the + * next line. I don't think this matters for text items. */ + curitem = CreateTextItem(text, startLine, linenum); + text = NULL; + if(tail == NULL) { + head = tail = curitem; + } else { + tail->next = curitem; + tail = curitem; + } + } + + /* Process the tag */ + tagp = ProcessTag(fb, &tagerr); + if(!tagp) { + if(tagerr) { + PR_fprintf(errorFD, "Error in file %s: %s\n", + filename, tagerr); + errorCount++; + } else { + PR_fprintf(errorFD, + "Error in file %s, in tag starting at line %d\n", + filename, linenum); + errorCount++; + } + goto loser; + } + /* Add the tag to the list */ + curitem = CreateTagItem(tagp, linenum, FB_GetLineNum(fb)); + if(tail == NULL) { + head = tail = curitem; + } else { + tail->next = curitem; + tail = curitem; + } + + /* What's the next state */ + if(tagp->type == SCRIPT_TAG) { + state = SCRIPT_HTML_STATE; + } + + /* Start recording text from the new offset */ + textStart = FB_GetPointer(fb); + startLine = FB_GetLineNum(fb); + } else { + /* regular character. Next! */ + } + break; + case SCRIPT_HTML_STATE: + if(curchar == '<') { + char *cp; + /* + * If this is a </script> tag, then we're at the end of the + * script. Otherwise, ignore + */ + curOffset = FB_GetPointer(fb)-1; + cp = NULL; + if(FB_GetRange(fb, curOffset, curOffset+8, &cp) != 9) { + if(cp) { PR_Free(cp); cp = NULL; } + } else { + /* compare the strings */ + if( !PORT_Strncasecmp(cp, "</script>", 9) ) { + /* This is the end of the script. Record the text. */ + curOffset--; + if(curOffset >= textStart) { + if(FB_GetRange(fb, textStart, curOffset, &text) != + curOffset-textStart+1) { + PR_fprintf(errorFD, + "Unable to read from %s.\n", filename); + errorCount++; + goto loser; + } + curitem = CreateTextItem(text, startLine, linenum); + text = NULL; + if(tail == NULL) { + head = tail = curitem; + } else { + tail->next = curitem; + tail = curitem; + } + } + + /* Now parse the /script tag and put it on the list */ + tagp = ProcessTag(fb, &tagerr); + if(!tagp) { + if(tagerr) { + PR_fprintf(errorFD, + "Error in file %s: %s\n", filename, tagerr); + } else { + PR_fprintf(errorFD, + "Error in file %s, in tag starting at" + " line %d\n", filename, linenum); + } + errorCount++; + goto loser; + } + curitem = CreateTagItem(tagp, linenum, + FB_GetLineNum(fb)); + if(tail == NULL) { + head = tail = curitem; + } else { + tail->next = curitem; + tail = curitem; + } + + /* go back to text state */ + state = TEXT_HTML_STATE; + + textStart = FB_GetPointer(fb); + startLine = FB_GetLineNum(fb); + } + } + } + break; + } + } + + /* End of the file. Wrap up any remaining text */ + if(state == SCRIPT_HTML_STATE) { + if(tail && tail->type==TAG_ITEM) { + PR_fprintf(errorFD, "ERROR: <SCRIPT> tag at %s:%d is not followed " + "by a </SCRIPT> tag.\n", filename, tail->startLine); + } else { + PR_fprintf(errorFD, "ERROR: <SCRIPT> tag in file %s is not followed" + " by a </SCRIPT tag.\n", filename); + } + errorCount++; + goto loser; + } + curOffset = FB_GetPointer(fb)-1; + if(curOffset >= textStart) { + text = NULL; + if( FB_GetRange(fb, textStart, curOffset, &text) != + curOffset-textStart+1) { + PR_fprintf(errorFD, "Unable to read from %s.\n", filename); + errorCount++; + goto loser; + } + curitem = CreateTextItem(text, startLine, linenum); + text = NULL; + if(tail == NULL) { + head = tail = curitem; + } else { + tail->next = curitem; + tail = curitem; + } + } + + if(dumpParse) { + PrintHTMLStream(outputFD, head); + } + + + + + /* + * Now we have a stream of tags and text. Go through and deal with each. + */ + for(curitem = head; curitem; curitem = curitem->next) { + TagItem *tagp=NULL; + AVPair *pairp=NULL; + char *src=NULL, *id=NULL, *codebase=NULL; + PRBool hasEventHandler=PR_FALSE; + int i; + + /* Reset archive directory for each tag */ + if(archiveDir) { + PR_Free(archiveDir); archiveDir = NULL; + } + + /* We only analyze tags */ + if(curitem->type != TAG_ITEM) { + continue; + } + + tagp = curitem->item.tag; + + /* go through the attributes to get information */ + for(pairp=tagp->attList; pairp; pairp=pairp->next) { + + /* ARCHIVE= */ + if( !PL_strcasecmp(pairp->attribute, "archive")) { + if(archiveDir) { + /* Duplicate attribute. Print warning */ + PR_fprintf(errorFD, + "warning: \"%s\" attribute overwrites previous attribute" + " in tag starting at %s:%d.\n", + pairp->attribute, filename, curitem->startLine); + warningCount++; + PR_Free(archiveDir); + } + archiveDir = PL_strdup(pairp->value); + + /* Substiture ".arc" for ".jar" */ + if( (PL_strlen(archiveDir)<4) || + PL_strcasecmp((archiveDir+strlen(archiveDir)-4), ".jar")){ + PR_fprintf(errorFD, + "warning: ARCHIVE attribute should end in \".jar\" in tag" + " starting on %s:%d.\n", filename, curitem->startLine); + warningCount++; + PR_Free(archiveDir); + archiveDir = PR_smprintf("%s.arc", archiveDir); + } else { + PL_strcpy(archiveDir+strlen(archiveDir)-4, ".arc"); + } + + /* Record the first archive. This will be used later if + * the archive is not specified */ + if(firstArchiveDir == NULL) { + firstArchiveDir = PL_strdup(archiveDir); + } + } + + /* CODEBASE= */ + else if( !PL_strcasecmp(pairp->attribute, "codebase")) { + if(codebase) { + /* Duplicate attribute. Print warning */ + PR_fprintf(errorFD, + "warning: \"%s\" attribute overwrites previous attribute" + " in tag staring at %s:%d.\n", + pairp->attribute, filename, curitem->startLine); + warningCount++; + } + codebase = pairp->value; + } + + /* SRC= and HREF= */ + else if( !PORT_Strcasecmp(pairp->attribute, "src") || + !PORT_Strcasecmp(pairp->attribute, "href") ) { + if(src) { + /* Duplicate attribute. Print warning */ + PR_fprintf(errorFD, + "warning: \"%s\" attribute overwrites previous attribute" + " in tag staring at %s:%d.\n", + pairp->attribute, filename, curitem->startLine); + warningCount++; + } + src = pairp->value; + } + + /* CODE= */ + else if(!PORT_Strcasecmp(pairp->attribute, "code") ) { + /*!!!XXX Change PORT to PL all over this code !!! */ + if(src) { + /* Duplicate attribute. Print warning */ + PR_fprintf(errorFD, + "warning: \"%s\" attribute overwrites previous attribute" + " ,in tag staring at %s:%d.\n", + pairp->attribute, filename, curitem->startLine); + warningCount++; + } + src = pairp->value; + + /* Append a .class if one is not already present */ + if( (PL_strlen(src)<6) || + PL_strcasecmp( (src + PL_strlen(src) - 6), ".class") ) { + src = PR_smprintf("%s.class", src); + /* Put this string back into the data structure so it + * will be deallocated properly */ + PR_Free(pairp->value); + pairp->value = src; + } + } + + /* ID= */ + else if (!PL_strcasecmp(pairp->attribute, "id") ) { + if(id) { + /* Duplicate attribute. Print warning */ + PR_fprintf(errorFD, + "warning: \"%s\" attribute overwrites previous attribute" + " in tag staring at %s:%d.\n", + pairp->attribute, filename, curitem->startLine); + warningCount++; + } + id = pairp->value; + } + + /* STYLE= */ + /* style= attributes, along with JS entities, are stored into + * files with dynamically generated names. The filenames are + * based on the order in which the text is found in the file. + * All JS entities on all lines up to and including the line + * containing the end of the tag that has this style= attribute + * will be processed before this style=attribute. So we need + * to record the line that this _tag_ (not the attribute) ends on. + */ + else if(!PL_strcasecmp(pairp->attribute, "style") && pairp->value) { + HTMLItem *styleItem; + /* Put this item on the style list */ + styleItem = CreateTextItem(PL_strdup(pairp->value), + curitem->startLine, curitem->endLine); + if(styleListTail == NULL) { + styleList = styleListTail = styleItem; + } else { + styleListTail->next = styleItem; + styleListTail = styleItem; + } + } + + /* Event handlers */ + else { + for(i=0; i < num_handlers; i++) { + if(!PL_strcasecmp(event_handlers[i], pairp->attribute)) { + hasEventHandler = PR_TRUE; + break; + } + } + } + + /* JS Entity */ + { + char *entityStart, *entityEnd; + HTMLItem *entityItem; + + /* go through each JavaScript entity ( &{...}; ) and store it + * in the entityList. The important thing is to record what + * line number it's on, so we can get it in the right order + * in relation to style= attributes. + * Apparently, these can't flow across lines, so the start and + * end line will be the same. That helps matters. + */ + entityEnd = pairp->value; + while( entityEnd && + (entityStart = PL_strstr(entityEnd, "&{")) != NULL) { + entityStart +=2; /* point at beginning of actual entity */ + entityEnd = PL_strstr(entityStart, "}"); + if(entityEnd) { + /* Put this item on the entity list */ + *entityEnd = '\0'; + entityItem = CreateTextItem(PL_strdup(entityStart), + pairp->valueLine, pairp->valueLine); + *entityEnd = '}'; + if(entityListTail) { + entityListTail->next = entityItem; + entityListTail = entityItem; + } else { + entityList = entityListTail = entityItem; + } + } + } + } + + } + + /* If no archive was supplied, we use the first one of the file */ + if(!archiveDir && firstArchiveDir) { + archiveDir = PL_strdup(firstArchiveDir); + } + + /* If we have an event handler, we need to archive this tag */ + if(hasEventHandler) { + if(!id) { + PR_fprintf(errorFD, + "warning: tag starting at %s:%d has event handler but" + " no ID attribute. The tag will not be signed.\n", + filename, curitem->startLine); + warningCount++; + } else if(!archiveDir) { + PR_fprintf(errorFD, + "warning: tag starting at %s:%d has event handler but" + " no ARCHIVE attribute. The tag will not be signed.\n", + filename, curitem->startLine); + warningCount++; + } else { + if(SaveInlineScript(tagp->text, id, basedir, archiveDir)) { + goto loser; + } + } + } + + switch(tagp->type) { + case APPLET_TAG: + if(!src) { + PR_fprintf(errorFD, + "error: APPLET tag starting on %s:%d has no CODE " + "attribute.\n", filename, curitem->startLine); + errorCount++; + goto loser; + } else if(!archiveDir) { + PR_fprintf(errorFD, + "error: APPLET tag starting on %s:%d has no ARCHIVE " + "attribute.\n", filename, curitem->startLine); + errorCount++; + goto loser; + } else { + if(SaveSource(src, codebase, basedir, archiveDir)) { + goto loser; + } + } + break; + case SCRIPT_TAG: + case LINK_TAG: + case STYLE_TAG: + if(!archiveDir) { + PR_fprintf(errorFD, + "error: %s tag starting on %s:%d has no ARCHIVE " + "attribute.\n", TagTypeToString(tagp->type), + filename, curitem->startLine); + errorCount++; + goto loser; + } else if(src) { + if(SaveSource(src, codebase, basedir, archiveDir)) { + goto loser; + } + } else if(id) { + /* Save the next text item */ + if(!curitem->next || (curitem->next->type != TEXT_ITEM)) { + PR_fprintf(errorFD, + "warning: %s tag starting on %s:%d is not followed" + " by script text.\n", TagTypeToString(tagp->type), + filename, curitem->startLine); + warningCount++; + /* just create empty file */ + if(SaveInlineScript("", id, basedir, archiveDir)) { + goto loser; + } + } else { + curitem = curitem->next; + if(SaveInlineScript(curitem->item.text, id, basedir, + archiveDir)){ + goto loser; + } + } + } else { + /* No src or id tag--warning */ + PR_fprintf(errorFD, + "warning: %s tag starting on %s:%d has no SRC or" + " ID attributes. Will not sign.\n", + TagTypeToString(tagp->type), filename, curitem->startLine); + warningCount++; + } + break; + default: + /* do nothing for other tags */ + break; + } + + } + + /* Now deal with all the unnamable scripts */ + if(firstArchiveDir) { + HTMLItem *style, *entity; + + /* Go through the lists of JS entities and style attributes. Do them + * in chronological order within a list. Pick the list with the lower + * endLine. In case of a tie, entities come first. + */ + style = styleList; entity = entityList; + while(style || entity) { + if(!entity || (style && (style->endLine < entity->endLine))) { + /* Process style */ + SaveUnnamableScript(style->item.text, basedir, firstArchiveDir, + filename); + style=style->next; + } else { + /* Process entity */ + SaveUnnamableScript(entity->item.text, basedir, firstArchiveDir, + filename); + entity=entity->next; + } + } + } + + + retval = 0; +loser: + /* Blow away the stream */ + while(head) { + curitem = head; + head = head->next; + DestroyHTMLItem(curitem); + } + while(styleList) { + curitem = styleList; + styleList = styleList->next; + DestroyHTMLItem(curitem); + } + while(entityList) { + curitem = entityList; + entityList = entityList->next; + DestroyHTMLItem(curitem); + } + if(text) { + PR_Free(text); text=NULL; + } + if(fb) { + FB_Destroy(fb); fb=NULL; + } + if(fd) { + PR_Close(fd); + } + if(tagerr) { + PR_smprintf_free(tagerr); tagerr=NULL; + } + if(archiveDir) { + PR_Free(archiveDir); archiveDir=NULL; + } + if(firstArchiveDir) { + PR_Free(firstArchiveDir); firstArchiveDir=NULL; + } + return retval; +} + +/********************************************************************** + * + * e n s u r e E x i s t s + * + * Check for existence of indicated directory. If it doesn't exist, + * it will be created. + * Returns PR_SUCCESS if the directory is present, PR_FAILURE otherwise. + */ +static PRStatus +ensureExists (char *base, char *path) +{ + char fn [FNSIZE]; + PRDir *dir; + sprintf (fn, "%s/%s", base, path); + + /*PR_fprintf(outputFD, "Trying to open directory %s.\n", fn);*/ + + if( (dir=PR_OpenDir(fn)) ) { + PR_CloseDir(dir); + return PR_SUCCESS; + } + return PR_MkDir(fn, 0777); +} + +/*************************************************************************** + * + * m a k e _ d i r s + * + * Ensure that the directory portion of the path exists. This may require + * making the directory, and its parent, and its parent's parent, etc. + */ +static int +make_dirs(char *path, int file_perms) +{ + char *Path; + char *start; + char *sep; + int ret = 0; + PRFileInfo info; + + if(!path) { + return 0; + } + + Path = PL_strdup(path); + start = strpbrk(Path, "/\\"); + if(!start) { + return 0; + } + start++; /* start right after first slash */ + + /* Each time through the loop add one more directory. */ + while( (sep=strpbrk(start, "/\\")) ) { + *sep = '\0'; + + if( PR_GetFileInfo(Path, &info) != PR_SUCCESS) { + /* No such dir, we have to create it */ + if( PR_MkDir(Path, file_perms) != PR_SUCCESS) { + PR_fprintf(errorFD, "ERROR: Unable to create directory %s.\n", + Path); + errorCount++; + ret = -1; + goto loser; + } + } else { + /* something exists by this name, make sure it's a directory */ + if( info.type != PR_FILE_DIRECTORY ) { + PR_fprintf(errorFD, "ERROR: Unable to create directory %s.\n", + Path); + errorCount++; + ret = -1; + goto loser; + } + } + + start = sep+1; /* start after the next slash */ + *sep = '/'; + } + +loser: + PR_Free(Path); + return ret; +} + +/* + * c o p y i n t o + * + * Function to copy file "from" to path "to". + * + */ +static int +copyinto (char *from, char *to) +{ + PRInt32 num; + char buf [BUFSIZ]; + PRFileDesc *infp=NULL, *outfp=NULL; + int retval = -1; + + if ((infp = PR_Open(from, PR_RDONLY, 0777)) == NULL) { + PR_fprintf(errorFD, "ERROR: Unable to open \"%s\" for reading.\n", + from); + errorCount++; + goto finish; + } + + /* If to already exists, print a warning before deleting it */ + if(PR_Access(to, PR_ACCESS_EXISTS) == PR_SUCCESS) { + PR_fprintf(errorFD, "warning: %s already exists--will overwrite\n", + to); + warningCount++; + if(rm_dash_r(to)) { + PR_fprintf(errorFD, + "ERROR: Unable to remove %s.\n", to); + errorCount++; + goto finish; + } + } + + if ((outfp = PR_Open(to, PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 0777)) + == NULL) { + char *errBuf=NULL; + + errBuf = PR_Malloc(PR_GetErrorTextLength()); + PR_fprintf(errorFD, "ERROR: Unable to open \"%s\" for writing.\n", + to); + if(PR_GetErrorText(errBuf)) { + PR_fprintf(errorFD, "Cause: %s\n", errBuf); + } + if(errBuf) { + PR_Free(errBuf); + } + errorCount++; + goto finish; + } + + while( (num = PR_Read(infp, buf, BUFSIZ)) >0) { + if(PR_Write(outfp, buf, num) != num) { + PR_fprintf(errorFD, "ERROR: Error writing to %s.\n", to); + errorCount++; + goto finish; + } + } + + retval = 0; +finish: + if(infp) PR_Close(infp); + if(outfp) PR_Close(outfp); + + return retval; +} diff --git a/security/nss/cmd/signtool/list.c b/security/nss/cmd/signtool/list.c new file mode 100644 index 000000000..33ec93d93 --- /dev/null +++ b/security/nss/cmd/signtool/list.c @@ -0,0 +1,278 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "signtool.h" +#include "pk11func.h" +#include "certdb.h" + +static int num_trav_certs = 0; +static SECStatus cert_trav_callback(CERTCertificate *cert, SECItem *k, + void *data); + +/********************************************************************* + * + * L i s t C e r t s + */ +int +ListCerts(char *key, int list_certs) +{ + int failed = 0; + SECStatus rv; + char *ugly_list; + CERTCertDBHandle *db; + + CERTCertificate *cert; + CERTVerifyLog errlog; + + errlog.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if( errlog.arena == NULL) { + out_of_memory(); + } + errlog.head = NULL; + errlog.tail = NULL; + errlog.count = 0; + + ugly_list = PORT_ZAlloc (16); + + if (ugly_list == NULL) { + out_of_memory(); + } + + *ugly_list = 0; + + db= CERT_GetDefaultCertDB(); + + if (list_certs == 2) { + PR_fprintf(outputFD, "\nS Certificates\n"); + PR_fprintf(outputFD, "- ------------\n"); + } else { + PR_fprintf(outputFD, "\nObject signing certificates\n"); + PR_fprintf(outputFD, "---------------------------------------\n"); + } + + num_trav_certs = 0; + + /* Traverse non-internal DBs */ + rv = PK11_TraverseSlotCerts(cert_trav_callback, (void*)&list_certs, + NULL /*wincx*/); + + if (rv) { + PR_fprintf(outputFD, "**Traverse of non-internal DBs failed**\n"); + return -1; + } + + if (num_trav_certs == 0) { + PR_fprintf(outputFD, + "You don't appear to have any object signing certificates.\n"); + } + + if (list_certs == 2) { + PR_fprintf(outputFD, "- ------------\n"); + } else { + PR_fprintf(outputFD, "---------------------------------------\n"); + } + + if (list_certs == 1) { + PR_fprintf(outputFD, + "For a list including CA's, use \"%s -L\"\n", PROGRAM_NAME); + } + + if(list_certs == 2) { + PR_fprintf(outputFD, + "Certificates that can be used to sign objects have *'s to " + "their left.\n"); + } + + if (key) { + /* Do an analysis of the given cert */ + + cert = PK11_FindCertFromNickname(key, NULL /*wincx*/); + + if (cert) { + PR_fprintf(outputFD, + "\nThe certificate with nickname \"%s\" was found:\n", + cert->nickname); + PR_fprintf(outputFD, + "\tsubject name: %s\n", cert->subjectName); + PR_fprintf(outputFD, + "\tissuer name: %s\n", cert->issuerName); + + PR_fprintf(outputFD, "\n"); + + rv = CERT_CertTimesValid (cert); + if(rv != SECSuccess) { + PR_fprintf(outputFD, "**This certificate is expired**\n"); + } else { + PR_fprintf(outputFD, "This certificate is not expired.\n"); + } + + rv = CERT_VerifyCert (db, cert, PR_TRUE, + certUsageObjectSigner, PR_Now(), NULL, &errlog); + + if (rv != SECSuccess) { + failed = 1; + if(errlog.count > 0) { + PR_fprintf(outputFD, + "**Certificate validation failed for the " + "following reason(s):**\n"); + } else { + PR_fprintf(outputFD, "**Certificate validation failed**"); + } + } else { + PR_fprintf(outputFD, "This certificate is valid.\n"); + } + displayVerifyLog(&errlog); + + + } else { + failed = 1; + PR_fprintf(outputFD, + "The certificate with nickname \"%s\" was NOT FOUND\n", + key); + } + } + + if(errlog.arena != NULL) { + PORT_FreeArena(errlog.arena, PR_FALSE); + } + + if (failed) { + return -1; + } + return 0; +} + +/******************************************************************** + * + * c e r t _ t r a v _ c a l l b a c k + */ +static SECStatus +cert_trav_callback(CERTCertificate *cert, SECItem *k, void *data) +{ + int isSigningCert; + int list_certs = 1; + + char *name, *issuerCN, *expires; + CERTCertificate *issuerCert = NULL; + + if(data) { + list_certs = *((int*)data); + } + + if (cert->nickname) + { + name = cert->nickname; + + isSigningCert = cert->nsCertType & NS_CERT_TYPE_OBJECT_SIGNING; + issuerCert = CERT_FindCertIssuer (cert, PR_Now(), certUsageObjectSigner); + issuerCN = CERT_GetCommonName (&cert->issuer); + + if (!isSigningCert && list_certs == 1) + return (SECSuccess); + + /* Add this name or email to list */ + + if (name) + { + int rv; + + num_trav_certs++; + if(list_certs == 2) { + PR_fprintf(outputFD, "%s ", isSigningCert ? "*" : " "); + } + PR_fprintf(outputFD, "%s\n", name); + + if (list_certs == 1) + { + if(issuerCert == NULL) { + PR_fprintf(outputFD, + "\t++ Error ++ Unable to find issuer certificate\n"); + return SECSuccess; /*function was a success even if cert is bogus*/ + } + if (issuerCN == NULL) + PR_fprintf(outputFD, " Issued by: %s\n", issuerCert->nickname); + else + PR_fprintf(outputFD, + " Issued by: %s (%s)\n", issuerCert->nickname, issuerCN); + + expires = DER_UTCDayToAscii (&cert->validity.notAfter); + + if (expires) + PR_fprintf(outputFD, " Expires: %s\n", expires); + + rv = CERT_CertTimesValid (cert); + + if (rv != SECSuccess) + PR_fprintf(outputFD, " ++ Error ++ THIS CERTIFICATE IS EXPIRED\n"); + + if (rv == SECSuccess) + { + rv = CERT_VerifyCertNow (cert->dbhandle, cert, + PR_TRUE, certUsageObjectSigner, NULL); + + if (rv != SECSuccess) + { + rv = PORT_GetError(); + PR_fprintf(outputFD, + " ++ Error ++ THIS CERTIFICATE IS NOT VALID (%s)\n", + secErrorString(rv)); } + } + + expires = DER_UTCDayToAscii (&issuerCert->validity.notAfter); + if (expires == NULL) expires = "(unknown)"; + + rv = CERT_CertTimesValid (issuerCert); + + if (rv != SECSuccess) + PR_fprintf(outputFD, + " ++ Error ++ ISSUER CERT \"%s\" EXPIRED ON %s\n", + issuerCert->nickname, expires); + + if (rv == SECSuccess) + { + rv = CERT_VerifyCertNow (issuerCert->dbhandle, issuerCert, + PR_TRUE, certUsageVerifyCA, NULL); + if (rv != SECSuccess) + { + rv = PORT_GetError(); + PR_fprintf(outputFD, + " ++ Error ++ ISSUER CERT \"%s\" IS NOT VALID (%s)\n", issuerCert->nickname, secErrorString(rv)); + } + } + } + } + } + + return (SECSuccess); +} + diff --git a/security/nss/cmd/signtool/manifest.mn b/security/nss/cmd/signtool/manifest.mn new file mode 100644 index 000000000..448734056 --- /dev/null +++ b/security/nss/cmd/signtool/manifest.mn @@ -0,0 +1,57 @@ +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +MODULE = nss + +EXPORTS = + +CSRCS = signtool.c \ + certgen.c \ + javascript.c \ + list.c \ + sign.c \ + util.c \ + verify.c \ + zip.c \ + $(NULL) + +PROGRAM = signtool + +REQUIRES = dbm seccmd + +DEFINES += -DNSPR20 + +USE_STATIC_LIBS = 1 + +EXTRA_LIBS = $(JAR_LIBS) diff --git a/security/nss/cmd/signtool/sign.c b/security/nss/cmd/signtool/sign.c new file mode 100644 index 000000000..59323c92d --- /dev/null +++ b/security/nss/cmd/signtool/sign.c @@ -0,0 +1,861 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "signtool.h" +#include "zip.h" +#include "prmem.h" +#include "blapi.h" +#include "sechash.h" /* for HASH_GetHashObject() */ + +static int create_pk7 (char *dir, char *keyName, int *keyType); +static int jar_find_key_type (CERTCertificate *cert); +static int manifesto (char *dirname, char *install_script, PRBool recurse); +static int manifesto_fn(char *relpath, char *basedir, char *reldir, + char *filename, void *arg); +static int sign_all_arc_fn(char *relpath, char *basedir, char *reldir, + char *filename, void *arg); +static int add_meta (FILE *fp, char *name); +static int SignFile (FILE *outFile, FILE *inFile, CERTCertificate *cert); +static int generate_SF_file (char *manifile, char *who); +static int calculate_MD5_range (FILE *fp, long r1, long r2, JAR_Digest *dig); +static void SignOut (void *arg, const char *buf, unsigned long len); + +static char *metafile = NULL; +static int optimize = 0; +static FILE *mf; +static ZIPfile *zipfile=NULL; + +/* + * S i g n A r c h i v e + * + * Sign an individual archive tree. A directory + * called META-INF is created underneath this. + * + */ +int +SignArchive(char *tree, char *keyName, char *zip_file, int javascript, + char *meta_file, char *install_script, int _optimize, PRBool recurse) +{ + int status; + char tempfn [FNSIZE], fullfn [FNSIZE]; + int keyType = rsaKey; + + metafile = meta_file; + optimize = _optimize; + + if(zip_file) { + zipfile = JzipOpen(zip_file, NULL /*no comment*/); + } + + manifesto (tree, install_script, recurse); + + if (keyName) + { + status = create_pk7 (tree, keyName, &keyType); + if (status < 0) + { + PR_fprintf(errorFD, "the tree \"%s\" was NOT SUCCESSFULLY SIGNED\n", tree); + errorCount++; + exit (ERRX); + } + } + + /* mf to zip */ + + strcpy (tempfn, "META-INF/manifest.mf"); + sprintf (fullfn, "%s/%s", tree, tempfn); + JzipAdd(fullfn, tempfn, zipfile, compression_level); + + /* sf to zip */ + + sprintf (tempfn, "META-INF/%s.sf", base); + sprintf (fullfn, "%s/%s", tree, tempfn); + JzipAdd(fullfn, tempfn, zipfile, compression_level); + + /* rsa/dsa to zip */ + + sprintf (tempfn, "META-INF/%s.%s", base, (keyType==dsaKey ? "dsa" : "rsa")); + sprintf (fullfn, "%s/%s", tree, tempfn); + JzipAdd(fullfn, tempfn, zipfile, compression_level); + + JzipClose(zipfile); + + if(verbosity >= 0) { + if (javascript) { + PR_fprintf(outputFD,"jarfile \"%s\" signed successfully\n", + zip_file); + } else { + PR_fprintf(outputFD, "tree \"%s\" signed successfully\n", tree); + } + } + + return 0; +} + +typedef struct { + char *keyName; + int javascript; + char *metafile; + char *install_script; + int optimize; +} SignArcInfo; + +/* + * S i g n A l l A r c + * + * Javascript may generate multiple .arc directories, one + * for each jar archive needed. Sign them all. + * + */ +int +SignAllArc(char *jartree, char *keyName, int javascript, char *metafile, + char *install_script, int optimize, PRBool recurse) +{ + SignArcInfo info; + + info.keyName = keyName; + info.javascript = javascript; + info.metafile = metafile; + info.install_script = install_script; + info.optimize = optimize; + + return foreach(jartree, "", sign_all_arc_fn, recurse, + PR_TRUE /*include dirs*/, (void*)&info); +} + +static int +sign_all_arc_fn(char *relpath, char *basedir, char *reldir, char *filename, + void *arg) +{ + char *zipfile=NULL; + char *arc=NULL, *archive=NULL; + int retval=0; + SignArcInfo *infop = (SignArcInfo*)arg; + + /* Make sure there is one and only one ".arc" in the relative path, + * and that it is at the end of the path (don't sign .arcs within .arcs) */ + if ( (PL_strcaserstr(relpath, ".arc") == relpath + strlen(relpath) - 4) && + (PL_strcasestr(relpath, ".arc") == relpath + strlen(relpath) - 4) ) { + + if(!infop) { + PR_fprintf(errorFD, "%s: Internal failure\n", PROGRAM_NAME); + errorCount++; + retval = -1; + goto finish; + } + archive = PR_smprintf("%s/%s", basedir, relpath); + + zipfile = PL_strdup(archive); + arc = PORT_Strrchr (zipfile, '.'); + + if (arc == NULL) { + PR_fprintf(errorFD, "%s: Internal failure\n", PROGRAM_NAME); + errorCount++; + retval = -1; + goto finish; + } + + PL_strcpy (arc, ".jar"); + + if(verbosity >= 0) { + PR_fprintf(outputFD, "\nsigning: %s\n", zipfile); + } + retval = SignArchive(archive, infop->keyName, zipfile, + infop->javascript, infop->metafile, infop->install_script, + infop->optimize, PR_TRUE /* recurse */); + } +finish: + if(archive) PR_Free(archive); + if(zipfile) PR_Free(zipfile); + + return retval; +} + +/********************************************************************* + * + * c r e a t e _ p k 7 + */ +static int +create_pk7 (char *dir, char *keyName, int *keyType) +{ + int status = 0; + char *file_ext; + + CERTCertificate *cert; + CERTCertDBHandle *db; + + FILE *in, *out; + + char sf_file [FNSIZE]; + char pk7_file [FNSIZE]; + + + /* open cert database */ + db = CERT_GetDefaultCertDB(); + + if (db == NULL) + return -1; + + + /* find cert */ + /*cert = CERT_FindCertByNicknameOrEmailAddr(db, keyName);*/ + cert = PK11_FindCertFromNickname(keyName, NULL /*wincx*/); + + if (cert == NULL) + { + SECU_PrintError + ( + PROGRAM_NAME, + "the cert \"%s\" does not exist in the database", + keyName + ); + return -1; + } + + + /* determine the key type, which sets the extension for pkcs7 object */ + + *keyType = jar_find_key_type (cert); + file_ext = (*keyType == dsaKey) ? "dsa" : "rsa"; + + sprintf (sf_file, "%s/META-INF/%s.sf", dir, base); + sprintf (pk7_file, "%s/META-INF/%s.%s", dir, base, file_ext); + + if ((in = fopen (sf_file, "rb")) == NULL) + { + PR_fprintf(errorFD, "%s: Can't open %s for reading\n", PROGRAM_NAME, sf_file); + errorCount++; + exit (ERRX); + } + + if ((out = fopen (pk7_file, "wb")) == NULL) + { + PR_fprintf(errorFD, "%s: Can't open %s for writing\n", PROGRAM_NAME, sf_file); + errorCount++; + exit (ERRX); + } + + status = SignFile (out, in, cert); + + CERT_DestroyCertificate (cert); + fclose (in); + fclose (out); + + if (status) + { + PR_fprintf(errorFD, "%s: PROBLEM signing data (%s)\n", + PROGRAM_NAME, SECU_ErrorString ((int16) PORT_GetError())); + errorCount++; + return -1; + } + + return 0; +} + +/* + * j a r _ f i n d _ k e y _ t y p e + * + * Determine the key type for a given cert, which + * should be rsaKey or dsaKey. Any error return 0. + * + */ +static int +jar_find_key_type (CERTCertificate *cert) +{ + PK11SlotInfo *slot = NULL; + SECKEYPrivateKey *privk = NULL; + KeyType keyType; + + /* determine its type */ + PK11_FindObjectForCert (cert, /*wincx*/ NULL, &slot); + + if (slot == NULL) + { + PR_fprintf(errorFD, "warning - can't find slot for this cert\n"); + warningCount++; + return 0; + } + + privk = PK11_FindPrivateKeyFromCert (slot, cert, /*wincx*/ NULL); + PK11_FreeSlot (slot); + + if (privk == NULL) + { + PR_fprintf(errorFD, "warning - can't find private key for this cert\n"); + warningCount++; + return 0; + } + + keyType = privk->keyType; + SECKEY_DestroyPrivateKey (privk); + return keyType; + } + + +/* + * m a n i f e s t o + * + * Run once for every subdirectory in which a + * manifest is to be created -- usually exactly once. + * + */ +static int +manifesto (char *dirname, char *install_script, PRBool recurse) +{ + char metadir [FNSIZE], sfname [FNSIZE]; + + /* Create the META-INF directory to hold signing info */ + + if (PR_Access (dirname, PR_ACCESS_READ_OK)) + { + PR_fprintf(errorFD, "%s: unable to read your directory: %s\n", PROGRAM_NAME, + dirname); + errorCount++; + perror (dirname); + exit (ERRX); + } + + if (PR_Access (dirname, PR_ACCESS_WRITE_OK)) { + PR_fprintf(errorFD, "%s: unable to write to your directory: %s\n", + PROGRAM_NAME, dirname); + errorCount++; + perror(dirname); + exit(ERRX); + } + + sprintf (metadir, "%s/META-INF", dirname); + + strcpy (sfname, metadir); + + PR_MkDir (metadir, 0777); + + strcat (metadir, "/"); + strcat (metadir, MANIFEST); + + if ((mf = fopen (metadir, "wb")) == NULL) + { + perror (MANIFEST); + PR_fprintf(errorFD, "%s: Probably, the directory you are trying to" + + " sign has\n", PROGRAM_NAME); + PR_fprintf(errorFD, "%s: permissions problems or may not exist.\n", + PROGRAM_NAME); + errorCount++; + exit (ERRX); + } + + if(verbosity >= 0) { + PR_fprintf(outputFD, "Generating %s file..\n", metadir); + } + + fprintf(mf, "Manifest-Version: 1.0\n"); + fprintf (mf, "Created-By: %s\n", CREATOR); + fprintf (mf, "Comments: %s\n", BREAKAGE); + + if (scriptdir) + { + fprintf (mf, "Comments: --\n"); + fprintf (mf, "Comments: --\n"); + fprintf (mf, "Comments: -- This archive signs Javascripts which may not necessarily\n"); + fprintf (mf, "Comments: -- be included in the physical jar file.\n"); + fprintf (mf, "Comments: --\n"); + fprintf (mf, "Comments: --\n"); + } + + if (install_script) + fprintf (mf, "Install-Script: %s\n", install_script); + + if (metafile) + add_meta (mf, "+"); + + /* Loop through all files & subdirectories */ + foreach (dirname, "", manifesto_fn, recurse, PR_FALSE /*include dirs */, + (void*)NULL); + + fclose (mf); + + strcat (sfname, "/"); + strcat (sfname, base); + strcat (sfname, ".sf"); + + if(verbosity >= 0) { + PR_fprintf(outputFD, "Generating %s.sf file..\n", base); + } + generate_SF_file (metadir, sfname); + + return 0; +} + +/* + * m a n i f e s t o _ f n + * + * Called by pointer from manifesto(), once for + * each file within the directory. + * + */ +static int manifesto_fn + (char *relpath, char *basedir, char *reldir, char *filename, void *arg) +{ + int use_js; + + JAR_Digest dig; + char fullname [FNSIZE]; + + if(verbosity >= 0) { + PR_fprintf(outputFD, "--> %s\n", relpath); + } + + /* extension matching */ + if(extensionsGiven) { + char *ext; + + ext = PL_strrchr(relpath, '.'); + if(!ext) { + return 0; + } else { + if(!PL_HashTableLookup(extensions, ext)) { + return 0; + } + } + } + + sprintf (fullname, "%s/%s", basedir, relpath); + + fprintf (mf, "\n"); + + use_js = 0; + + if (scriptdir && !PORT_Strcmp (scriptdir, reldir)) + use_js++; + + /* sign non-.js files inside .arc directories + using the javascript magic */ + + if ( (PL_strcaserstr(filename, ".js") != filename + strlen(filename) - 3) + && (PL_strcaserstr(reldir, ".arc") == reldir + strlen(filename)-4)) + use_js++; + + if (use_js) + { + fprintf (mf, "Name: %s\n", filename); + fprintf (mf, "Magic: javascript\n"); + + if (optimize == 0) + fprintf (mf, "javascript.id: %s\n", filename); + + if (metafile) + add_meta (mf, filename); + } + else + { + fprintf (mf, "Name: %s\n", relpath); + if (metafile) + add_meta (mf, relpath); + } + + JAR_digest_file (fullname, &dig); + + + if (optimize == 0) + { + fprintf (mf, "Digest-Algorithms: MD5 SHA1\n"); + fprintf (mf, "MD5-Digest: %s\n", BTOA_DataToAscii (dig.md5, MD5_LENGTH)); + } + + fprintf (mf, "SHA1-Digest: %s\n", BTOA_DataToAscii (dig.sha1, SHA1_LENGTH)); + + if(!use_js) { + JzipAdd(fullname, relpath, zipfile, compression_level); + } + + return 0; +} + +/* + * a d d _ m e t a + * + * Parse the metainfo file, and add any details + * necessary to the manifest file. In most cases you + * should be using the -i option (ie, for SmartUpdate). + * + */ +static int add_meta (FILE *fp, char *name) +{ + FILE *met; + char buf [BUFSIZ]; + + int place; + char *pattern, *meta; + + int num = 0; + + if ((met = fopen (metafile, "r")) != NULL) + { + while (fgets (buf, BUFSIZ, met)) + { + char *s; + + for (s = buf; *s && *s != '\n' && *s != '\r'; s++); + *s = 0; + + if (*buf == 0) + continue; + + pattern = buf; + + /* skip to whitespace */ + for (s = buf; *s && *s != ' ' && *s != '\t'; s++); + + /* terminate pattern */ + if (*s == ' ' || *s == '\t') *s++ = 0; + + /* eat through whitespace */ + while (*s == ' ' || *s == '\t') s++; + + meta = s; + + /* this will eventually be regexp matching */ + + place = 0; + if (!PORT_Strcmp (pattern, name)) + place = 1; + + if (place) + { + num++; + if(verbosity >= 0) { + PR_fprintf(outputFD, "[%s] %s\n", name, meta); + } + fprintf (fp, "%s\n", meta); + } + } + fclose (met); + } + else + { + PR_fprintf(errorFD, "%s: can't open metafile: %s\n", PROGRAM_NAME, metafile); + errorCount++; + exit (ERRX); + } + + return num; +} + +/********************************************************************** + * + * S i g n F i l e + */ +static int +SignFile (FILE *outFile, FILE *inFile, CERTCertificate *cert) +{ + int nb; + char ibuf[4096], digestdata[32]; + const SECHashObject *hashObj; + void *hashcx; + unsigned int len; + + SECItem digest; + SEC_PKCS7ContentInfo *cinfo; + SECStatus rv; + + if (outFile == NULL || inFile == NULL || cert == NULL) + return -1; + + /* XXX probably want to extend interface to allow other hash algorithms */ + hashObj = HASH_GetHashObject(HASH_AlgSHA1); + + hashcx = (* hashObj->create)(); + if (hashcx == NULL) + return -1; + + (* hashObj->begin)(hashcx); + + for (;;) + { + if (feof(inFile)) break; + nb = fread(ibuf, 1, sizeof(ibuf), inFile); + if (nb == 0) + { + if (ferror(inFile)) + { + PORT_SetError(SEC_ERROR_IO); + (* hashObj->destroy)(hashcx, PR_TRUE); + return -1; + } + /* eof */ + break; + } + (* hashObj->update)(hashcx, (unsigned char *) ibuf, nb); + } + + (* hashObj->end)(hashcx, (unsigned char *) digestdata, &len, 32); + (* hashObj->destroy)(hashcx, PR_TRUE); + + digest.data = (unsigned char *) digestdata; + digest.len = len; + + cinfo = SEC_PKCS7CreateSignedData + (cert, certUsageObjectSigner, NULL, + SEC_OID_SHA1, &digest, NULL, NULL); + + if (cinfo == NULL) + return -1; + + rv = SEC_PKCS7IncludeCertChain (cinfo, NULL); + if (rv != SECSuccess) + { + SEC_PKCS7DestroyContentInfo (cinfo); + return -1; + } + + if (no_time == 0) + { + rv = SEC_PKCS7AddSigningTime (cinfo); + if (rv != SECSuccess) + { + /* don't check error */ + } + } + + if(password) { + rv = SEC_PKCS7Encode(cinfo, SignOut, outFile, NULL, + (SECKEYGetPasswordKey) password_hardcode, NULL); + } else { + rv = SEC_PKCS7Encode(cinfo, SignOut, outFile, NULL, NULL, + NULL); + } + + + SEC_PKCS7DestroyContentInfo (cinfo); + + if (rv != SECSuccess) + return -1; + + return 0; +} + +/* + * g e n e r a t e _ S F _ f i l e + * + * From the supplied manifest file, calculates + * digests on the various sections, creating a .SF + * file in the process. + * + */ +static int generate_SF_file (char *manifile, char *who) +{ + FILE *sf; + FILE *mf; + + long r1, r2, r3; + + char whofile [FNSIZE]; + char *buf, *name = NULL; + + JAR_Digest dig; + + int line = 0; + + strcpy (whofile, who); + + if ((mf = fopen (manifile, "rb")) == NULL) + { + perror (manifile); + exit (ERRX); + } + + if ((sf = fopen (whofile, "wb")) == NULL) + { + perror (who); + exit (ERRX); + } + + buf = (char *) PORT_ZAlloc (BUFSIZ); + + if (buf) + name = (char *) PORT_ZAlloc (BUFSIZ); + + if (buf == NULL || name == NULL) + out_of_memory(); + + fprintf (sf, "Signature-Version: 1.0\n"); + fprintf (sf, "Created-By: %s\n", CREATOR); + fprintf (sf, "Comments: %s\n", BREAKAGE); + + if (fgets (buf, BUFSIZ, mf) == NULL) + { + PR_fprintf(errorFD, "%s: empty manifest file!\n", PROGRAM_NAME); + errorCount++; + exit (ERRX); + } + + if (strncmp (buf, "Manifest-Version:", 17)) + { + PR_fprintf(errorFD, "%s: not a manifest file!\n", PROGRAM_NAME); + errorCount++; + exit (ERRX); + } + + fseek (mf, 0L, SEEK_SET); + + /* Process blocks of headers, and calculate their hashen */ + + while (1) + { + /* Beginning range */ + r1 = ftell (mf); + + if (fgets (name, BUFSIZ, mf) == NULL) + break; + + line++; + + if (r1 != 0 && strncmp (name, "Name:", 5)) + { + PR_fprintf(errorFD, "warning: unexpected input in manifest file \"%s\" at line %d:\n", manifile, line); + PR_fprintf(errorFD, "%s\n", name); + warningCount++; + } + + r2 = r1; + while (fgets (buf, BUFSIZ, mf)) + { + if (*buf == 0 || *buf == '\n' || *buf == '\r') + break; + + line++; + + /* Ending range for hashing */ + r2 = ftell (mf); + } + + r3 = ftell (mf); + + if (r1) + { + fprintf (sf, "\n"); + fprintf (sf, "%s", name); + } + + calculate_MD5_range (mf, r1, r2, &dig); + + if (optimize == 0) + { + fprintf (sf, "Digest-Algorithms: MD5 SHA1\n"); + fprintf (sf, "MD5-Digest: %s\n", + BTOA_DataToAscii (dig.md5, MD5_LENGTH)); + } + + fprintf (sf, "SHA1-Digest: %s\n", + BTOA_DataToAscii (dig.sha1, SHA1_LENGTH)); + + /* restore normalcy after changing offset position */ + fseek (mf, r3, SEEK_SET); + } + + PORT_Free (buf); + PORT_Free (name); + + fclose (sf); + fclose (mf); + + return 0; +} + +/* + * c a l c u l a t e _ M D 5 _ r a n g e + * + * Calculate the MD5 digest on a range of bytes in + * the specified fopen'd file. Returns base64. + * + */ +static int +calculate_MD5_range (FILE *fp, long r1, long r2, JAR_Digest *dig) +{ + int num; + int range; + unsigned char *buf; + + MD5Context *md5 = 0; + SHA1Context *sha1 = 0; + + unsigned int sha1_length, md5_length; + + range = r2 - r1; + + /* position to the beginning of range */ + fseek (fp, r1, SEEK_SET); + + buf = (unsigned char *) PORT_ZAlloc (range); + if (buf == NULL) + out_of_memory(); + + if ((num = fread (buf, 1, range, fp)) != range) + { + PR_fprintf(errorFD, "%s: expected %d bytes, got %d\n", PROGRAM_NAME, + range, num); + errorCount++; + exit (ERRX); + } + + md5 = MD5_NewContext(); + sha1 = SHA1_NewContext(); + + if (md5 == NULL || sha1 == NULL) + { + PR_fprintf(errorFD, "%s: can't generate digest context\n", PROGRAM_NAME); + errorCount++; + exit (ERRX); + } + + MD5_Begin (md5); + SHA1_Begin (sha1); + + MD5_Update (md5, buf, range); + SHA1_Update (sha1, buf, range); + + MD5_End (md5, dig->md5, &md5_length, MD5_LENGTH); + SHA1_End (sha1, dig->sha1, &sha1_length, SHA1_LENGTH); + + MD5_DestroyContext (md5, PR_TRUE); + SHA1_DestroyContext (sha1, PR_TRUE); + + PORT_Free (buf); + + return 0; +} + +static void SignOut (void *arg, const char *buf, unsigned long len) +{ + fwrite (buf, len, 1, (FILE *) arg); +} diff --git a/security/nss/cmd/signtool/signtool.c b/security/nss/cmd/signtool/signtool.c new file mode 100644 index 000000000..4e0236825 --- /dev/null +++ b/security/nss/cmd/signtool/signtool.c @@ -0,0 +1,1054 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* + * SIGNTOOL + * + * A command line tool to create manifest files + * from a directory hierarchy. It is assumed that + * the tree will be equivalent to what resides + * or will reside in an archive. + * + * + */ + +#include "signtool.h" +#include <prmem.h> +#include <prio.h> + +/*********************************************************************** + * Global Variable Definitions + */ +char *progName; /* argv[0] */ + +/* password on command line. Use for build testing only */ +char *password = NULL; + +/* directories or files to exclude in descent */ +PLHashTable *excludeDirs = NULL; +static PRBool exclusionsGiven = PR_FALSE; + +/* zatharus is the man who knows no time, dies tragic death */ +int no_time = 0; + +/* -b basename of .rsa, .sf files */ +char *base = DEFAULT_BASE_NAME; + +/* Only sign files with this extension */ +PLHashTable *extensions=NULL; +PRBool extensionsGiven = PR_FALSE; + +char *scriptdir = NULL; + +int verbosity = 0; + +PRFileDesc *outputFD=NULL, *errorFD=NULL; + +int errorCount=0, warningCount=0; + +int compression_level=DEFAULT_COMPRESSION_LEVEL; +PRBool compression_level_specified = PR_FALSE; + +/* Command-line arguments */ +static char *genkey = NULL; +static char *verify = NULL; +static char *zipfile = NULL; +static char *cert_dir = NULL; +static int javascript = 0; +static char *jartree = NULL; +static char *keyName = NULL; +static char *metafile = NULL; +static char *install_script = NULL; +static int list_certs = 0; +static int list_modules = 0; +static int optimize = 0; +static int enableOCSP = 0; +static char *tell_who = NULL; +static char *outfile = NULL; +static char *cmdFile = NULL; +static PRBool noRecurse = PR_FALSE; +static PRBool leaveArc = PR_FALSE; +static int keySize = -1; +static char *token = NULL; + +typedef enum { + UNKNOWN_OPT, + QUESTION_OPT, + BASE_OPT, + COMPRESSION_OPT, + CERT_DIR_OPT, + EXTENSION_OPT, + INSTALL_SCRIPT_OPT, + SCRIPTDIR_OPT, + CERTNAME_OPT, + LIST_OBJSIGN_CERTS_OPT, + LIST_ALL_CERTS_OPT, + METAFILE_OPT, + OPTIMIZE_OPT, + ENABLE_OCSP_OPT, + PASSWORD_OPT, + VERIFY_OPT, + WHO_OPT, + EXCLUDE_OPT, + NO_TIME_OPT, + JAVASCRIPT_OPT, + ZIPFILE_OPT, + GENKEY_OPT, + MODULES_OPT, + NORECURSE_OPT, + SIGNDIR_OPT, + OUTFILE_OPT, + COMMAND_FILE_OPT, + LEAVE_ARC_OPT, + VERBOSITY_OPT, + KEYSIZE_OPT, + TOKEN_OPT +} OPT_TYPE; + +typedef enum { + DUPLICATE_OPTION_ERR=0, + OPTION_NEEDS_ARG_ERR +} Error; + +static char *errStrings[] = { +"warning: %s option specified more than once. Only last specification will be used.\n", +"ERROR: option \"%s\" requires an argument.\n" +}; + + +static int ProcessOneOpt(OPT_TYPE type, char *arg); + +/********************************************************************* + * + * P r o c e s s C o m m a n d F i l e + */ +int +ProcessCommandFile() +{ + PRFileDesc *fd; +#define CMD_FILE_BUFSIZE 1024 + char buf[CMD_FILE_BUFSIZE]; + char *equals; + int linenum=0; + int retval=-1; + OPT_TYPE type; + + fd = PR_Open(cmdFile, PR_RDONLY, 0777); + if(!fd) { + PR_fprintf(errorFD, "ERROR: Unable to open command file %s.\n"); + errorCount++; + return -1; + } + + while(pr_fgets(buf, CMD_FILE_BUFSIZE, fd), buf && *buf!='\0') { + char *eol; + linenum++; + + /* Chop off final newline */ + eol = PL_strchr(buf, '\r'); + if(!eol) { + eol = PL_strchr(buf, '\n'); + } + if(eol) *eol = '\0'; + + equals = PL_strchr(buf, '='); + if(!equals) { + continue; + } + + *equals = '\0'; + equals++; + + /* Now buf points to the attribute, and equals points to the value. */ + + /* This is pretty straightforward, just deal with whatever attribute + * this is */ + if(!PL_strcasecmp(buf, "basename")) { + type = BASE_OPT; + } else if(!PL_strcasecmp(buf, "compression")) { + type = COMPRESSION_OPT; + } else if(!PL_strcasecmp(buf, "certdir")) { + type = CERT_DIR_OPT; + } else if(!PL_strcasecmp(buf, "extension")) { + type = EXTENSION_OPT; + } else if(!PL_strcasecmp(buf, "generate")) { + type = GENKEY_OPT; + } else if(!PL_strcasecmp(buf, "installScript")) { + type = INSTALL_SCRIPT_OPT; + } else if(!PL_strcasecmp(buf, "javascriptdir")) { + type = SCRIPTDIR_OPT; + } else if(!PL_strcasecmp(buf, "htmldir")) { + type = JAVASCRIPT_OPT; + if(jartree) { + PR_fprintf(errorFD, + "warning: directory to be signed specified more than once." + " Only last specification will be used.\n"); + warningCount++; + PR_Free(jartree); jartree=NULL; + } + jartree = PL_strdup(equals); + } else if(!PL_strcasecmp(buf, "certname")) { + type = CERTNAME_OPT; + } else if(!PL_strcasecmp(buf, "signdir")) { + type = SIGNDIR_OPT; + } else if(!PL_strcasecmp(buf, "list")) { + type = LIST_OBJSIGN_CERTS_OPT; + } else if(!PL_strcasecmp(buf, "listall")) { + type = LIST_ALL_CERTS_OPT; + } else if(!PL_strcasecmp(buf, "metafile")) { + type = METAFILE_OPT; + } else if(!PL_strcasecmp(buf, "modules")) { + type = MODULES_OPT; + } else if(!PL_strcasecmp(buf, "optimize")) { + type = OPTIMIZE_OPT; + } else if(!PL_strcasecmp(buf, "ocsp")) { + type = ENABLE_OCSP_OPT; + } else if(!PL_strcasecmp(buf, "password")) { + type = PASSWORD_OPT; + } else if(!PL_strcasecmp(buf, "verify")) { + type = VERIFY_OPT; + } else if(!PL_strcasecmp(buf, "who")) { + type = WHO_OPT; + } else if(!PL_strcasecmp(buf, "exclude")) { + type = EXCLUDE_OPT; + } else if(!PL_strcasecmp(buf, "notime")) { + type = NO_TIME_OPT; + } else if(!PL_strcasecmp(buf, "jarfile")) { + type = ZIPFILE_OPT; + } else if(!PL_strcasecmp(buf, "outfile")) { + type = OUTFILE_OPT; + } else if(!PL_strcasecmp(buf, "leavearc")) { + type = LEAVE_ARC_OPT; + } else if(!PL_strcasecmp(buf, "verbosity")) { + type = VERBOSITY_OPT; + } else if(!PL_strcasecmp(buf, "keysize")) { + type = KEYSIZE_OPT; + } else if(!PL_strcasecmp(buf, "token")) { + type = TOKEN_OPT; + } else { + PR_fprintf(errorFD, + "warning: unknown attribute \"%s\" in command file, line %d.\n", + buf, linenum); + warningCount++; + type = UNKNOWN_OPT; + } + + /* Process the option, whatever it is */ + if(type != UNKNOWN_OPT) { + if(ProcessOneOpt(type, equals)==-1) { + goto finish; + } + } + } + + retval = 0; + +finish: + PR_Close(fd); + return retval; +} + +/********************************************************************* + * + * p a r s e _ a r g s + */ +static int +parse_args(int argc, char *argv[]) +{ + char *opt; + char *arg; + int needsInc = 0; + int i; + OPT_TYPE type; + + /* Loop over all arguments */ + for(i=1; i < argc; i++) { + opt = argv[i]; + arg = NULL; + + if(opt[0] == '-') { + if(opt[1] == '-') { + /* word option */ + if(i < argc-1) { + needsInc = 1; + arg = argv[i+1]; + } else { + arg = NULL; + } + + if( !PL_strcasecmp(opt+2, "norecurse")) { + type = NORECURSE_OPT; + } else if( !PL_strcasecmp(opt+2, "leavearc")) { + type = LEAVE_ARC_OPT; + } else if( !PL_strcasecmp(opt+2, "verbosity")) { + type = VERBOSITY_OPT; + } else if( !PL_strcasecmp(opt+2, "outfile")) { + type = OUTFILE_OPT; + } else if( !PL_strcasecmp(opt+2, "keysize")) { + type = KEYSIZE_OPT; + } else if( !PL_strcasecmp(opt+2, "token")) { + type = TOKEN_OPT; + } else { + PR_fprintf(errorFD, "warning: unknown option: %s\n", opt); + warningCount++; + type = UNKNOWN_OPT; + } + } else { + /* char option */ + if(opt[2]!='\0') { + arg = opt+2; + } else if(i < argc-1) { + needsInc = 1; + arg = argv[i+1]; + } else { + arg = NULL; + } + + switch(opt[1]) { + case '?': + type = QUESTION_OPT; + break; + case 'b': + type = BASE_OPT; + break; + case 'c': + type = COMPRESSION_OPT; + break; + case 'd': + type = CERT_DIR_OPT; + break; + case 'e': + type = EXTENSION_OPT; + break; + case 'f': + type = COMMAND_FILE_OPT; + break; + case 'i': + type = INSTALL_SCRIPT_OPT; + break; + case 'j': + type = SCRIPTDIR_OPT; + break; + case 'k': + type = CERTNAME_OPT; + break; + case 'l': + type = LIST_OBJSIGN_CERTS_OPT; + break; + case 'L': + type = LIST_ALL_CERTS_OPT; + break; + case 'm': + type = METAFILE_OPT; + break; + case 'o': + type = OPTIMIZE_OPT; + break; + case 'O': + type = ENABLE_OCSP_OPT; + break; + case 'p': + type = PASSWORD_OPT; + break; + case 'v': + type = VERIFY_OPT; + break; + case 'w': + type = WHO_OPT; + break; + case 'x': + type = EXCLUDE_OPT; + break; + case 'z': + type = NO_TIME_OPT; + break; + case 'J': + type = JAVASCRIPT_OPT; + break; + case 'Z': + type = ZIPFILE_OPT; + break; + case 'G': + type = GENKEY_OPT; + break; + case 'M': + type = MODULES_OPT; + break; + case 's': + type = KEYSIZE_OPT; + break; + case 't': + type = TOKEN_OPT; + break; + default: + type = UNKNOWN_OPT; + PR_fprintf(errorFD, "warning: unrecognized option: -%c.\n", + opt[1]); + warningCount++; + break; + } + } + } else { + type = UNKNOWN_OPT; + if(i == argc-1) { + if(jartree) { + PR_fprintf(errorFD, + "warning: directory to be signed specified more than once." + " Only last specification will be used.\n"); + warningCount++; + PR_Free(jartree); jartree = NULL; + } + jartree = PL_strdup(opt); + } else { + PR_fprintf(errorFD, "warning: unrecognized option: %s\n", opt); + warningCount++; + } + } + + if(type != UNKNOWN_OPT) { + short ateArg; + + ateArg = ProcessOneOpt(type, arg); + if(ateArg==-1) { + /* error */ + return -1; + } else if(ateArg && needsInc) { + i++; + } + } + } + + return 0; +} + +/********************************************************************* + * + * P r o c e s s O n e O p t + * + * Since options can come from different places (command file, word options, + * char options), this is a central function that is called to deal with + * them no matter where they come from. + * + * type is the type of option. + * arg is the argument to the option, possibly NULL. + * Returns 1 if the argument was eaten, 0 if it wasn't, and -1 for error. + */ +static int +ProcessOneOpt(OPT_TYPE type, char *arg) +{ + int ate=0; + + switch(type) { + case QUESTION_OPT: + usage(); + break; + case BASE_OPT: + if(base) { + PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-b"); + warningCount++; + PR_Free(base); base=NULL; + } + if(!arg) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-b"); + errorCount++; + goto loser; + } + base = PL_strdup(arg); + ate = 1; + break; + case COMPRESSION_OPT: + if(compression_level_specified) { + PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-c"); + warningCount++; + } + if( !arg ) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-c"); + errorCount++; + goto loser; + } + compression_level = atoi(arg); + compression_level_specified = PR_TRUE; + ate = 1; + break; + case CERT_DIR_OPT: + if(cert_dir) { + PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-d"); + warningCount++; + PR_Free(cert_dir); cert_dir = NULL; + } + if(!arg) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-d"); + errorCount++; + goto loser; + } + cert_dir = PL_strdup(arg); + ate = 1; + break; + case EXTENSION_OPT: + if(!arg) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], + "extension (-e)"); + errorCount++; + goto loser; + } + PL_HashTableAdd(extensions, arg, arg); + extensionsGiven = PR_TRUE; + ate = 1; + break; + case INSTALL_SCRIPT_OPT: + if(install_script) { + PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], + "installScript (-i)"); + warningCount++; + PR_Free(install_script); install_script = NULL; + } + if(!arg) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], + "installScript (-i)"); + errorCount++; + goto loser; + } + install_script = PL_strdup(arg); + ate = 1; + break; + case SCRIPTDIR_OPT: + if(scriptdir) { + PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], + "javascriptdir (-j)"); + warningCount++; + PR_Free(scriptdir); scriptdir = NULL; + } + if(!arg) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], + "javascriptdir (-j)"); + errorCount++; + goto loser; + } + scriptdir = PL_strdup(arg); + ate = 1; + break; + case CERTNAME_OPT: + if(keyName) { + PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], + "keyName (-k)"); + warningCount++; + PR_Free(keyName); keyName = NULL; + } + if(!arg) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], + "keyName (-k)"); + errorCount++; + goto loser; + } + keyName = PL_strdup(arg); + ate = 1; + break; + case LIST_OBJSIGN_CERTS_OPT: + case LIST_ALL_CERTS_OPT: + if(list_certs != 0) { + PR_fprintf(errorFD, + "warning: only one of -l and -L may be specified.\n"); + warningCount++; + } + list_certs = (type==LIST_OBJSIGN_CERTS_OPT ? 1 : 2); + break; + case METAFILE_OPT: + if(metafile) { + PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], + "metafile (-m)"); + warningCount++; + PR_Free(metafile); metafile = NULL; + } + if(!arg) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], + "metafile (-m)"); + errorCount++; + goto loser; + } + metafile = PL_strdup(arg); + ate = 1; + break; + case OPTIMIZE_OPT: + optimize = 1; + break; + case ENABLE_OCSP_OPT: + enableOCSP = 1; + break; + case PASSWORD_OPT: + if(password) { + PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], + "password (-p)"); + warningCount++; + PR_Free(password); password= NULL; + } + if(!arg) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], + "password (-p)"); + errorCount++; + goto loser; + } + password = PL_strdup(arg); + ate = 1; + break; + case VERIFY_OPT: + if(verify) { + PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], + "verify (-v)"); + warningCount++; + PR_Free(verify); verify = NULL; + } + if(!arg) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], + "verify (-v)"); + errorCount++; + goto loser; + } + verify = PL_strdup(arg); + ate = 1; + break; + case WHO_OPT: + if(tell_who) { + PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], + "who (-v)"); + warningCount++; + PR_Free(tell_who); tell_who = NULL; + } + if(!arg) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], + "who (-w)"); + errorCount++; + goto loser; + } + tell_who = PL_strdup(arg); + ate = 1; + break; + case EXCLUDE_OPT: + if(!arg) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], + "exclude (-x)"); + errorCount++; + goto loser; + } + PL_HashTableAdd(excludeDirs, arg, arg); + exclusionsGiven = PR_TRUE; + ate = 1; + break; + case NO_TIME_OPT: + no_time = 1; + break; + case JAVASCRIPT_OPT: + javascript++; + break; + case ZIPFILE_OPT: + if(zipfile) { + PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], + "jarfile (-Z)"); + warningCount++; + PR_Free(zipfile); zipfile = NULL; + } + if(!arg) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], + "jarfile (-Z)"); + errorCount++; + goto loser; + } + zipfile = PL_strdup(arg); + ate = 1; + break; + case GENKEY_OPT: + if(genkey) { + PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], + "generate (-G)"); + warningCount++; + PR_Free(zipfile); zipfile = NULL; + } + if(!arg) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], + "generate (-G)"); + errorCount++; + goto loser; + } + genkey = PL_strdup(arg); + ate = 1; + break; + case MODULES_OPT: + list_modules++; + break; + case SIGNDIR_OPT: + if(jartree) { + PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], + "signdir"); + warningCount++; + PR_Free(jartree); jartree = NULL; + } + if(!arg) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "signdir"); + errorCount++; + goto loser; + } + jartree = PL_strdup(arg); + ate = 1; + break; + case OUTFILE_OPT: + if(outfile) { + PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], + "outfile"); + warningCount++; + PR_Free(outfile); outfile = NULL; + } + if(!arg) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "outfile"); + errorCount++; + goto loser; + } + outfile = PL_strdup(arg); + ate = 1; + break; + case COMMAND_FILE_OPT: + if(cmdFile) { + PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-f"); + warningCount++; + PR_Free(cmdFile); cmdFile = NULL; + } + if(!arg) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-f"); + errorCount++; + goto loser; + } + cmdFile = PL_strdup(arg); + ate = 1; + break; + case NORECURSE_OPT: + noRecurse = PR_TRUE; + break; + case LEAVE_ARC_OPT: + leaveArc = PR_TRUE; + break; + case VERBOSITY_OPT: + if(!arg) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], + "--verbosity"); + errorCount++; + goto loser; + } + verbosity = atoi(arg); + ate = 1; + break; + case KEYSIZE_OPT: + if( keySize != -1 ) { + PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-s"); + warningCount++; + } + keySize = atoi(arg); + ate = 1; + if( keySize < 1 || keySize > MAX_RSA_KEY_SIZE ) { + PR_fprintf(errorFD, "Invalid key size: %d.\n", keySize); + errorCount++; + goto loser; + } + break; + case TOKEN_OPT: + if( token ) { + PR_fprintf(errorFD, errStrings[DUPLICATE_OPTION_ERR], "-t"); + PR_Free(token); token = NULL; + } + if( ! arg ) { + PR_fprintf(errorFD, errStrings[OPTION_NEEDS_ARG_ERR], "-t"); + errorCount++; + goto loser; + } + token = PL_strdup(arg); + ate = 1; + break; + default: + PR_fprintf(errorFD, "warning: unknown option\n"); + warningCount++; + break; + } + + return ate; +loser: + return -1; +} + + +/********************************************************************* + * + * m a i n + */ +int +main(int argc, char *argv[]) +{ + PRBool readOnly; + int retval=0; + + outputFD = PR_STDOUT; + errorFD = PR_STDERR; + + progName = argv[0]; + + if (argc < 2) + { + usage(); + } + + excludeDirs = PL_NewHashTable(10, PL_HashString, PL_CompareStrings, + PL_CompareStrings, NULL, NULL); + extensions = PL_NewHashTable(10, PL_HashString, PL_CompareStrings, + PL_CompareStrings, NULL, NULL); + + if(parse_args(argc, argv)) { + retval = -1; + goto cleanup; + } + + /* Parse the command file if one was given */ + if(cmdFile) { + if(ProcessCommandFile()) { + retval = -1; + goto cleanup; + } + } + + /* Set up output redirection */ + if(outfile) { + if(PR_Access(outfile, PR_ACCESS_EXISTS)==PR_SUCCESS) { + /* delete the file if it is already present */ + PR_fprintf(errorFD, + "warning: %s already exists and will be overwritten.\n", + outfile); + warningCount++; + if(PR_Delete(outfile) != PR_SUCCESS) { + PR_fprintf(errorFD, "ERROR: unable to delete %s.\n", outfile); + errorCount++; + exit(ERRX); + } + } + outputFD = PR_Open(outfile, + PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 0777); + if(!outputFD) { + PR_fprintf(errorFD, "ERROR: Unable to create %s.\n", outfile); + errorCount++; + exit(ERRX); + } + errorFD = outputFD; + } + + /* This seems to be a fairly common user error */ + + if (verify && list_certs > 0) + { + PR_fprintf (errorFD, "%s: Can't use -l and -v at the same time\n", + PROGRAM_NAME); + errorCount++; + retval = -1; + goto cleanup; + } + + /* -J assumes -Z now */ + + if (javascript && zipfile) + { + PR_fprintf (errorFD, "%s: Can't use -J and -Z at the same time\n", + PROGRAM_NAME); + PR_fprintf (errorFD, "%s: -J option will create the jar files for you\n", + PROGRAM_NAME); + errorCount++; + retval = -1; + goto cleanup; + } + + /* Less common mixing of -L with various options */ + + if (list_certs > 0 && + (tell_who || zipfile || javascript || + scriptdir || extensionsGiven || exclusionsGiven || install_script)) { + PR_fprintf(errorFD, "%s: Can't use -l or -L with that option\n", + PROGRAM_NAME); + errorCount++; + retval = -1; + goto cleanup; + } + + + if (!cert_dir) + cert_dir = get_default_cert_dir(); + + VerifyCertDir(cert_dir, keyName); + + + if( compression_level < MIN_COMPRESSION_LEVEL || + compression_level > MAX_COMPRESSION_LEVEL) { + PR_fprintf(errorFD, "Compression level must be between %d and %d.\n", + MIN_COMPRESSION_LEVEL, MAX_COMPRESSION_LEVEL); + errorCount++; + retval = -1; + goto cleanup; + } + + if(jartree && !keyName) { + PR_fprintf(errorFD, "You must specify a key with which to sign.\n"); + errorCount++; + retval = -1; + goto cleanup; + } + + readOnly = (genkey == NULL); /* only key generation requires write */ + if(InitCrypto(cert_dir, readOnly)) { + PR_fprintf(errorFD, "ERROR: Cryptographic initialization failed.\n"); + errorCount++; + retval = -1; + goto cleanup; + } + + if (enableOCSP) { + SECStatus rv = CERT_EnableOCSPChecking(CERT_GetDefaultCertDB()); + if (rv != SECSuccess) { + PR_fprintf(errorFD, "ERROR: Attempt to enable OCSP Checking failed.\n"); + errorCount++; + retval = -1; + } + } + + if (verify) + { + if (VerifyJar(verify)) + { + errorCount++; + retval = -1; + goto cleanup; + } + } + else if (list_certs) + { + if (ListCerts(keyName, list_certs)) + { + errorCount++; + retval = -1; + goto cleanup; + } + } + else if (list_modules) + { + JarListModules(); + } + else if (genkey) + { + if (GenerateCert(genkey, keySize, token)) + { + errorCount++; + retval = -1; + goto cleanup; + } + } + else if (tell_who) + { + if (JarWho(tell_who)) + { + errorCount++; + retval = -1; + goto cleanup; + } + } + else if (javascript && jartree) + { + /* make sure directory exists */ + PRDir *dir; + dir = PR_OpenDir(jartree); + if(!dir) { + PR_fprintf(errorFD, "ERROR: unable to open directory %s.\n", jartree); + errorCount++; + retval = -1; + goto cleanup; + } else { + PR_CloseDir(dir); + } + + /* undo junk from prior runs of signtool*/ + if(RemoveAllArc(jartree)) { + PR_fprintf(errorFD, "Error removing archive directories under %s\n", jartree); + errorCount++; + retval = -1; + goto cleanup; + } + + /* traverse all the htm|html files in the directory */ + if(InlineJavaScript(jartree, !noRecurse)) { + retval = -1; + goto cleanup; + } + + /* sign any resultant .arc directories created in above step */ + if(SignAllArc(jartree, keyName, javascript, metafile, install_script, + optimize, !noRecurse)) { + retval = -1; + goto cleanup; + } + + if(!leaveArc) { + RemoveAllArc(jartree); + } + + if(errorCount>0 || warningCount>0) { + PR_fprintf(outputFD, "%d error%s, %d warning%s.\n", errorCount, + errorCount==1?"":"s", warningCount, warningCount==1?"":"s"); + } else { + PR_fprintf(outputFD, "Directory %s signed successfully.\n", jartree); + } + } else if (jartree) + { + SignArchive(jartree, keyName, zipfile, javascript, metafile, + install_script, optimize, !noRecurse); + } + else + usage(); + +cleanup: + if(extensions) { + PL_HashTableDestroy(extensions); extensions = NULL; + } + if(excludeDirs) { + PL_HashTableDestroy(excludeDirs); excludeDirs = NULL; + } + if(outputFD != PR_STDOUT) { + PR_Close(outputFD); + } + rm_dash_r(TMP_OUTPUT); + if (retval == 0) { + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + } + return retval; +} + diff --git a/security/nss/cmd/signtool/signtool.h b/security/nss/cmd/signtool/signtool.h new file mode 100644 index 000000000..5c6ad0284 --- /dev/null +++ b/security/nss/cmd/signtool/signtool.h @@ -0,0 +1,140 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 SIGNTOOL_H +#define SIGNTOOL_H + +#define DJN_TEST + +#include <stdio.h> +#include <string.h> +#include <errno.h> + +#include "prprf.h" +#include "prio.h" +#include "secutil.h" +#include "ocsp.h" +#include "jar.h" +#include "jarfile.h" +#include "secpkcs7.h" +#include "pk11func.h" +#include "secmod.h" +#include "plhash.h" + +#ifdef _UNIX +#include <unistd.h> +#endif + +/********************************************************************** + * General Defines + */ +#define JAR_BASE_END JAR_BASE + 100 +#define ERRX (-1) /* the exit code used on failure */ +#define FNSIZE 256 /* the maximum length for filenames */ +#define MAX_RSA_KEY_SIZE 4096 +#define DEFAULT_RSA_KEY_SIZE 1024 +#define MANIFEST "manifest.mf" +#define DEFAULT_X509_BASENAME "x509" +#define DEFAULT_COMMON_NAME "Signtool 1.3 Testing Certificate" +#define CREATOR "Signtool (signtool 1.3)" +#define BREAKAGE "PLEASE DO NOT EDIT THIS FILE. YOU WILL BREAK IT." +#define MIN_COMPRESSION_LEVEL (-1) +#define MAX_COMPRESSION_LEVEL 9 +#define DEFAULT_COMPRESSION_LEVEL (-1) /* zlib understands this to be default*/ +#define STDIN_BUF_SIZE 160 +#define PROGRAM_NAME "signtool" +#define LONG_PROGRAM_NAME "Signing Tool" +#define DEFAULT_BASE_NAME "zigbert" +#define VERSION "1.3" +#define TMP_OUTPUT "signtool.tmp" + + +/*************************************************************** + * Main Task Functions + */ +int GenerateCert(char *nickname, int keysize, char *token); +int ListCerts(char *key, int list_certs); +int VerifyJar(char *filename); +int SignArchive(char *tree, char *keyName, char *zip_file, int javascript, + char *meta_file, char *install_script, int _optimize, PRBool recurse); +int SignAllArc(char *jartree, char *keyName, int javascript, char *metafile, + char *install_script, int optimize, PRBool recurse); +int InlineJavaScript(char *dir, PRBool recurse); +int JarWho(char *filename); +void JarListModules(void); + +/************************************************************** + * Utility Functions + */ +CERTCertDBHandle *OpenCertDB (PRBool readOnly); + +int RemoveAllArc(char *tree); +void VerifyCertDir(char *dir, char *keyName); +int InitCrypto(char *cert_dir, PRBool readOnly); +int foreach (char *dirname, char *prefix, + int (*fn)(char *filename, char *dirname, char *basedir,char *base,void*arg), + PRBool recurse, PRBool includeDirs, void *arg); +void print_error (int i); +void give_help (int status); +const char* secErrorString(long code); +void displayVerifyLog(CERTVerifyLog *log); +void usage (void); +char* chop(char*); +void out_of_memory(void); +void FatalError(char *msg); +char* get_default_cert_dir(void); +SECItem *password_hardcode(void *arg, void *handle); +char* pk11_password_hardcode(PK11SlotInfo *slot, PRBool retry, void *arg); +int rm_dash_r(char *path); +char* pr_fgets(char *buf, int size, PRFileDesc *file); + + +/***************************************************************** + * Global Variables (*gag*) + */ +extern char *password; /* the password passed in on the command line */ +extern PLHashTable *excludeDirs; /* directory entry to skip while recursing */ +extern int no_time; +extern char *base; /* basename of ".rsa" and ".sf" files */ +extern long *mozilla_event_queue; +extern char *progName; /* argv[0] */ +extern PLHashTable *extensions;/* only sign files with this extension */ +extern PRBool extensionsGiven; +extern char *scriptdir; +extern int compression_level; +extern PRFileDesc *outputFD, *errorFD; +extern int verbosity; +extern int errorCount; +extern int warningCount; + +#endif /* SIGNTOOL_H */ diff --git a/security/nss/cmd/signtool/util.c b/security/nss/cmd/signtool/util.c new file mode 100644 index 000000000..c1b401e33 --- /dev/null +++ b/security/nss/cmd/signtool/util.c @@ -0,0 +1,990 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "signtool.h" +#include "prio.h" +#include "prmem.h" +#include "nss.h" + +static int is_dir (char *filename); + +/*********************************************************** + * Nasty hackish function definitions + */ + +long *mozilla_event_queue = 0; + +#ifndef XP_WIN +char *XP_GetString (int i) +{ + return SECU_ErrorStringRaw ((int16) i); +} +#endif + +void FE_SetPasswordEnabled() +{ +} + +void /*MWContext*/ *FE_GetInitContext (void) +{ + return 0; +} + +void /*MWContext*/ *XP_FindSomeContext() +{ + /* No windows context in command tools */ + return NULL; +} + +void ET_moz_CallFunction() +{ +} + + +/* + * R e m o v e A l l A r c + * + * Remove .arc directories that are lingering + * from a previous run of signtool. + * + */ +int +RemoveAllArc(char *tree) +{ + PRDir *dir; + PRDirEntry *entry; + char *archive=NULL; + int retval = 0; + + dir = PR_OpenDir (tree); + if (!dir) return -1; + + for (entry = PR_ReadDir (dir,0); entry; entry = PR_ReadDir (dir,0)) { + + if(entry->name[0] == '.') { + continue; + } + + if(archive) PR_Free(archive); + archive = PR_smprintf("%s/%s", tree, entry->name); + + if (PL_strcaserstr (entry->name, ".arc") + == (entry->name + strlen(entry->name) - 4) ) { + + if(verbosity >= 0) { + PR_fprintf(outputFD, "removing: %s\n", archive); + } + + if(rm_dash_r(archive)) { + PR_fprintf(errorFD, "Error removing %s\n", archive); + errorCount++; + retval = -1; + goto finish; + } + } else if(is_dir(archive)) { + if(RemoveAllArc(archive)) { + retval = -1; + goto finish; + } + } + } + +finish: + PR_CloseDir (dir); + if(archive) PR_Free(archive); + + return retval; +} + +/* + * r m _ d a s h _ r + * + * Remove a file, or a directory recursively. + * + */ +int rm_dash_r (char *path) +{ + PRDir *dir; + PRDirEntry *entry; + PRFileInfo fileinfo; + char filename[FNSIZE]; + + if(PR_GetFileInfo(path, &fileinfo) != PR_SUCCESS) { + /*fprintf(stderr, "Error: Unable to access %s\n", filename);*/ + return -1; + } + if(fileinfo.type == PR_FILE_DIRECTORY) { + + dir = PR_OpenDir(path); + if(!dir) { + PR_fprintf(errorFD, "Error: Unable to open directory %s.\n", path); + errorCount++; + return -1; + } + + /* Recursively delete all entries in the directory */ + while((entry = PR_ReadDir(dir, PR_SKIP_BOTH)) != NULL) { + sprintf(filename, "%s/%s", path, entry->name); + if(rm_dash_r(filename)) return -1; + } + + if(PR_CloseDir(dir) != PR_SUCCESS) { + PR_fprintf(errorFD, "Error: Could not close %s.\n", path); + errorCount++; + return -1; + } + + /* Delete the directory itself */ + if(PR_RmDir(path) != PR_SUCCESS) { + PR_fprintf(errorFD, "Error: Unable to delete %s\n", path); + errorCount++; + return -1; + } + } else { + if(PR_Delete(path) != PR_SUCCESS) { + PR_fprintf(errorFD, "Error: Unable to delete %s\n", path); + errorCount++; + return -1; + } + } + return 0; +} + +/* + * u s a g e + * + * Print some useful help information + * + */ +void +usage (void) +{ + PR_fprintf(outputFD, "\n"); + PR_fprintf(outputFD, "%s %s - a signing tool for jar files\n", LONG_PROGRAM_NAME, VERSION); + PR_fprintf(outputFD, "\n"); + PR_fprintf(outputFD, "Usage: %s [options] directory-tree \n\n", PROGRAM_NAME); + PR_fprintf(outputFD, " -b\"basename\"\t\tbasename of .sf, .rsa files for signing\n"); + PR_fprintf(outputFD, " -c#\t\t\t\tCompression level, 0-9, 0=none\n"); + PR_fprintf(outputFD, " -d\"certificate directory\"\tcontains cert*.db and key*.db\n"); + PR_fprintf(outputFD, " -e\".ext\"\t\t\tsign only files with this extension\n"); + PR_fprintf(outputFD, " -f\"filename\"\t\t\tread commands from file\n"); + PR_fprintf(outputFD, " -G\"nickname\"\t\tcreate object-signing cert with this nickname\n"); + PR_fprintf(outputFD, " -i\"installer script\"\tassign installer javascript\n"); + PR_fprintf(outputFD, " -j\"javascript directory\"\tsign javascript files in this subtree\n"); + PR_fprintf(outputFD, " -J\t\t\t\tdirectory contains HTML files. Javascript will\n" + "\t\t\t\tbe extracted and signed.\n"); + PR_fprintf(outputFD, " -k\"cert nickname\"\t\tsign with this certificate\n"); + PR_fprintf(outputFD, " --leavearc\t\t\tdo not delete .arc directories created\n" + "\t\t\t\tby -J option\n"); + PR_fprintf(outputFD, " -m\"metafile\"\t\tinclude custom meta-information\n"); + PR_fprintf(outputFD, " --norecurse\t\t\tdo not operate on subdirectories\n"); + PR_fprintf(outputFD, " -o\t\t\t\toptimize - omit optional headers\n"); + PR_fprintf(outputFD, " -O\t\t\t\tenableOCSP - enable OCSP checking\n"); + PR_fprintf(outputFD, " --outfile \"filename\"\tredirect output to file\n"); + PR_fprintf(outputFD, " -p\"password\"\t\tfor password on command line (insecure)\n"); + PR_fprintf(outputFD, " -s keysize\t\t\tkeysize in bits of generated cert\n"); + PR_fprintf(outputFD, " -t token\t\t\tname of token on which to generate cert\n"); + PR_fprintf(outputFD, " --verbosity #\t\tSet amount of debugging information to generate.\n" + "\t\t\t\tLower number means less output, 0 is default.\n"); + PR_fprintf(outputFD, " -x\"name\"\t\t\tdirectory or filename to exclude\n"); + PR_fprintf(outputFD, " -z\t\t\t\tomit signing time from signature\n"); + PR_fprintf(outputFD, " -Z\"jarfile\"\t\t\tcreate JAR file with the given name.\n" + "\t\t\t\t(Default compression level is 6.)\n"); + PR_fprintf(outputFD, "\n"); + PR_fprintf(outputFD, "%s -l\n", PROGRAM_NAME); + PR_fprintf(outputFD, " lists the signing certificates in your database\n"); + PR_fprintf(outputFD, "\n"); + PR_fprintf(outputFD, "%s -L\n", PROGRAM_NAME); + PR_fprintf(outputFD, " lists all certificates in your database, marks object-signing certificates\n"); + PR_fprintf(outputFD, "\n"); + PR_fprintf(outputFD, "%s -M\n", PROGRAM_NAME); + PR_fprintf(outputFD, " lists the PKCS #11 modules available to %s\n", PROGRAM_NAME); + PR_fprintf(outputFD, "\n"); + PR_fprintf(outputFD, "%s -v file.jar\n", PROGRAM_NAME); + PR_fprintf(outputFD, " show the contents of the specified jar file\n"); + PR_fprintf(outputFD, "\n"); + PR_fprintf(outputFD, "%s -w file.jar\n", PROGRAM_NAME); + PR_fprintf(outputFD, " if valid, tries to tell you who signed the jar file\n"); + PR_fprintf(outputFD, "\n"); + PR_fprintf(outputFD, "For more details, visit\n"); + PR_fprintf(outputFD, +" http://developer.netscape.com/library/documentation/signedobj/signtool/\n"); + + exit (ERRX); +} + +/* + * p r i n t _ e r r o r + * + * For the undocumented -E function. If an older version + * of communicator gives you a numeric error, we can see what + * really happened without doing hex math. + * + */ + +void +print_error (int err) +{ + PR_fprintf(errorFD, "Error %d: %s\n", err, JAR_get_error (err)); + errorCount++; + give_help (err); +} + +/* + * o u t _ o f _ m e m o r y + * + * Out of memory, exit Signtool. + * + */ +void +out_of_memory (void) +{ + PR_fprintf(errorFD, "%s: out of memory\n", PROGRAM_NAME); + errorCount++; + exit (ERRX); +} + +/* + * V e r i f y C e r t D i r + * + * Validate that the specified directory + * contains a certificate database + * + */ +void +VerifyCertDir(char *dir, char *keyName) +{ + char fn [FNSIZE]; + + /* don't try verifying if we don't have a local directory */ + if (strncmp(dir,"multiaccess:",sizeof("multiaccess:")-1) == 0) { + return; + } + + /* This code is really broken because it makes underlying assumptions about + * how the NSS profile directory is laid out, but these names can change + * from release to release. */ + sprintf (fn, "%s/cert8.db", dir); + + if (PR_Access (fn, PR_ACCESS_EXISTS)) + { + PR_fprintf(errorFD, "%s: No certificate database in \"%s\"\n", PROGRAM_NAME, + dir); + PR_fprintf(errorFD, "%s: Check the -d arguments that you gave\n", + PROGRAM_NAME); + errorCount++; + exit (ERRX); + } + + if(verbosity >= 0) { + PR_fprintf(outputFD, "using certificate directory: %s\n", dir); + } + + if (keyName == NULL) + return; + + /* if the user gave the -k key argument, verify that + a key database already exists */ + + sprintf (fn, "%s/key3.db", dir); + + if (PR_Access (fn, PR_ACCESS_EXISTS)) + { + PR_fprintf(errorFD, "%s: No private key database in \"%s\"\n", PROGRAM_NAME, + dir); + PR_fprintf(errorFD, "%s: Check the -d arguments that you gave\n", + PROGRAM_NAME); + errorCount++; + exit (ERRX); + } +} + +/* + * f o r e a c h + * + * A recursive function to loop through all names in + * the specified directory, as well as all subdirectories. + * + * FIX: Need to see if all platforms allow multiple + * opendir's to be called. + * + */ + +int +foreach(char *dirname, char *prefix, + int (*fn)(char *relpath, char *basedir, char *reldir, char *filename, + void* arg), + PRBool recurse, PRBool includeDirs, void *arg) { + char newdir [FNSIZE]; + int retval = 0; + + PRDir *dir; + PRDirEntry *entry; + + strcpy (newdir, dirname); + if (*prefix) { + strcat (newdir, "/"); + strcat (newdir, prefix); + } + + dir = PR_OpenDir (newdir); + if (!dir) return -1; + + for (entry = PR_ReadDir (dir,0); entry; entry = PR_ReadDir (dir,0)) { + if ( strcmp(entry->name, ".")==0 || + strcmp(entry->name, "..")==0 ) + { + /* no infinite recursion, please */ + continue; + } + + /* can't sign self */ + if (!strcmp (entry->name, "META-INF")) + continue; + + /* -x option */ + if (PL_HashTableLookup(excludeDirs, entry->name)) + continue; + + strcpy (newdir, dirname); + if (*dirname) + strcat (newdir, "/"); + + if (*prefix) { + strcat (newdir, prefix); + strcat (newdir, "/"); + } + strcat (newdir, entry->name); + + if(!is_dir(newdir) || includeDirs) { + char newpath [FNSIZE]; + + strcpy (newpath, prefix); + if (*newpath) + strcat (newpath, "/"); + strcat (newpath, entry->name); + + if( (*fn) (newpath, dirname, prefix, (char *) entry->name, arg)) { + retval = -1; + break; + } + } + + if (is_dir (newdir)) { + if(recurse) { + char newprefix [FNSIZE]; + + strcpy (newprefix, prefix); + if (*newprefix) { + strcat (newprefix, "/"); + } + strcat (newprefix, entry->name); + + if(foreach (dirname, newprefix, fn, recurse, includeDirs,arg)) { + retval = -1; + break; + } + } + } + + } + + PR_CloseDir (dir); + + return retval; +} + +/* + * i s _ d i r + * + * Return 1 if file is a directory. + * Wonder if this runs on a mac, trust not. + * + */ +static int is_dir (char *filename) +{ + PRFileInfo finfo; + + if( PR_GetFileInfo(filename, &finfo) != PR_SUCCESS ) { + printf("Unable to get information about %s\n", filename); + return 0; + } + + return ( finfo.type == PR_FILE_DIRECTORY ); +} + +/* + * p a s s w o r d _ h a r d c o d e + * + * A function to use the password passed in the -p(password) argument + * of the command line. This is only to be used for build & testing purposes, + * as it's extraordinarily insecure. + * + * After use once, null it out otherwise PKCS11 calls us forever. + * + */ +SECItem * +password_hardcode(void *arg, void *handle) +{ + SECItem *pw = NULL; + if (password) { + pw = SECITEM_AllocItem(NULL, NULL, PL_strlen(password)); + pw->data = (unsigned char *)PL_strdup(password); + password = NULL; + } + return pw; +} + +char * +pk11_password_hardcode(PK11SlotInfo *slot, PRBool retry, void *arg) +{ + char *pw; + if (retry) { + return NULL; /* the password is incorrect, fail */ + } + pw = password ? PORT_Strdup (password) : NULL; + /* XXX don't do this, or FIPS won't work */ + /*password = NULL;*/ + return pw; +} + +/************************************************************************ + * + * c e r t D B N a m e C a l l b a c k + */ +static char * +certDBNameCallback(void *arg, int dbVersion) +{ + char *fnarg; + char *dir; + char *filename; + + dir = SECU_ConfigDirectory (NULL); + + switch ( dbVersion ) { + case 7: + fnarg = "7"; + break; + case 6: + fnarg = "6"; + break; + case 5: + fnarg = "5"; + break; + case 4: + default: + fnarg = ""; + break; + } + filename = PR_smprintf("%s/cert%s.db", dir, fnarg); + return(filename); +} + +/*************************************************************** + * + * s e c E r r o r S t r i n g + * + * Returns an error string corresponding to the given error code. + * Doesn't cover all errors; returns a default for many. + * Returned string is only valid until the next call of this function. + */ +const char* +secErrorString(long code) +{ + static char errstring[80]; /* dynamically constructed error string */ + char *c; /* the returned string */ + + switch(code) { + case SEC_ERROR_IO: c = "io error"; + break; + case SEC_ERROR_LIBRARY_FAILURE: c = "security library failure"; + break; + case SEC_ERROR_BAD_DATA: c = "bad data"; + break; + case SEC_ERROR_OUTPUT_LEN: c = "output length"; + break; + case SEC_ERROR_INPUT_LEN: c = "input length"; + break; + case SEC_ERROR_INVALID_ARGS: c = "invalid args"; + break; + case SEC_ERROR_EXPIRED_CERTIFICATE: c = "expired certificate"; + break; + case SEC_ERROR_REVOKED_CERTIFICATE: c = "revoked certificate"; + break; + case SEC_ERROR_INADEQUATE_KEY_USAGE: c = "inadequate key usage"; + break; + case SEC_ERROR_INADEQUATE_CERT_TYPE: c = "inadequate certificate type"; + break; + case SEC_ERROR_UNTRUSTED_CERT: c = "untrusted cert"; + break; + case SEC_ERROR_NO_KRL: c = "no key revocation list"; + break; + case SEC_ERROR_KRL_BAD_SIGNATURE: c = "key revocation list: bad signature"; + break; + case SEC_ERROR_KRL_EXPIRED: c = "key revocation list expired"; + break; + case SEC_ERROR_REVOKED_KEY: c = "revoked key"; + break; + case SEC_ERROR_CRL_BAD_SIGNATURE: + c = "certificate revocation list: bad signature"; + break; + case SEC_ERROR_CRL_EXPIRED: c = "certificate revocation list expired"; + break; + case SEC_ERROR_CRL_NOT_YET_VALID: + c = "certificate revocation list not yet valid"; + break; + case SEC_ERROR_UNKNOWN_ISSUER: c = "unknown issuer"; + break; + case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: c = "expired issuer certificate"; + break; + case SEC_ERROR_BAD_SIGNATURE: c = "bad signature"; + break; + case SEC_ERROR_BAD_KEY: c = "bad key"; + break; + case SEC_ERROR_NOT_FORTEZZA_ISSUER: c = "not fortezza issuer"; + break; + case SEC_ERROR_CA_CERT_INVALID: + c = "Certificate Authority certificate invalid"; + break; + case SEC_ERROR_EXTENSION_NOT_FOUND: c = "extension not found"; + break; + case SEC_ERROR_CERT_NOT_IN_NAME_SPACE: c = "certificate not in name space"; + break; + case SEC_ERROR_UNTRUSTED_ISSUER: c = "untrusted issuer"; + break; + default: + sprintf(errstring, "security error %ld", code); + c = errstring; + break; + } + + return c; +} + +/*************************************************************** + * + * d i s p l a y V e r i f y L o g + * + * Prints the log of a cert verification. + */ +void +displayVerifyLog(CERTVerifyLog *log) +{ + CERTVerifyLogNode *node; + CERTCertificate *cert; + char *name; + + if( !log || (log->count <= 0) ) { + return; + } + + for(node = log->head; node != NULL; node = node->next) { + + if( !(cert = node->cert) ) { + continue; + } + + /* Get a name for this cert */ + if(cert->nickname != NULL) { + name = cert->nickname; + } else if(cert->emailAddr != NULL) { + name = cert->emailAddr; + } else { + name = cert->subjectName; + } + + printf( "%s%s:\n", + name, + (node->depth > 0) ? " [Certificate Authority]" : "" + ); + + printf("\t%s\n", secErrorString(node->error)); + + } +} +/* + * J a r L i s t M o d u l e s + * + * Print a list of the PKCS11 modules that are + * available. This is useful for smartcard people to + * make sure they have the drivers loaded. + * + */ +void +JarListModules(void) +{ + int i; + int count = 0; + + SECMODModuleList *modules = NULL; + static SECMODListLock *moduleLock = NULL; + + SECMODModuleList *mlp; + + modules = SECMOD_GetDefaultModuleList(); + + if (modules == NULL) + { + PR_fprintf(errorFD, "%s: Can't get module list\n", PROGRAM_NAME); + errorCount++; + exit (ERRX); + } + + if ((moduleLock = SECMOD_NewListLock()) == NULL) + { + /* this is the wrong text */ + PR_fprintf(errorFD, "%s: unable to acquire lock on module list\n", + PROGRAM_NAME); + errorCount++; + exit (ERRX); + } + + SECMOD_GetReadLock (moduleLock); + + PR_fprintf(outputFD, "\nListing of PKCS11 modules\n"); + PR_fprintf(outputFD, "-----------------------------------------------\n"); + + for (mlp = modules; mlp != NULL; mlp = mlp->next) + { + count++; + PR_fprintf(outputFD, "%3d. %s\n", count, mlp->module->commonName); + + if (mlp->module->internal) + PR_fprintf(outputFD, " (this module is internally loaded)\n"); + else + PR_fprintf(outputFD, " (this is an external module)\n"); + + if (mlp->module->dllName) + PR_fprintf(outputFD, " DLL name: %s\n", mlp->module->dllName); + + if (mlp->module->slotCount == 0) + PR_fprintf(outputFD, " slots: There are no slots attached to this module\n"); + else + PR_fprintf(outputFD, " slots: %d slots attached\n", mlp->module->slotCount); + + if (mlp->module->loaded == 0) + PR_fprintf(outputFD, " status: Not loaded\n"); + else + PR_fprintf(outputFD, " status: loaded\n"); + + for (i = 0; i < mlp->module->slotCount; i++) + { + PK11SlotInfo *slot = mlp->module->slots[i]; + + PR_fprintf(outputFD, "\n"); + PR_fprintf(outputFD, " slot: %s\n", PK11_GetSlotName(slot)); + PR_fprintf(outputFD, " token: %s\n", PK11_GetTokenName(slot)); + } + } + + PR_fprintf(outputFD, "-----------------------------------------------\n"); + + if (count == 0) + PR_fprintf(outputFD, + "Warning: no modules were found (should have at least one)\n"); + + SECMOD_ReleaseReadLock (moduleLock); +} + +/********************************************************************** + * c h o p + * + * Eliminates leading and trailing whitespace. Returns a pointer to the + * beginning of non-whitespace, or an empty string if it's all whitespace. + */ +char* +chop(char *str) +{ + char *start, *end; + + if(str) { + start = str; + + /* Nip leading whitespace */ + while(isspace(*start)) { + start++; + } + + /* Nip trailing whitespace */ + if(*start) { + end = start + strlen(start) - 1; + while(isspace(*end) && end > start) { + end--; + } + *(end+1) = '\0'; + } + + return start; + } else { + return NULL; + } +} + +/*********************************************************************** + * + * F a t a l E r r o r + * + * Outputs an error message and bails out of the program. + */ +void +FatalError(char *msg) +{ + if(!msg) msg = ""; + + PR_fprintf(errorFD, "FATAL ERROR: %s\n", msg); + errorCount++; + exit(ERRX); +} + +/************************************************************************* + * + * I n i t C r y p t o + */ +int +InitCrypto(char *cert_dir, PRBool readOnly) +{ + SECStatus rv; + static int prior = 0; + PK11SlotInfo *slotinfo; + + CERTCertDBHandle *db; + + if (prior == 0) { + /* some functions such as OpenKeyDB expect this path to be + * implicitly set prior to calling */ + if (readOnly) { + rv = NSS_Init(cert_dir); + } else { + rv = NSS_InitReadWrite(cert_dir); + } + if (rv != SECSuccess) { + SECU_PrintPRandOSError(PROGRAM_NAME); + exit(-1); + } + + SECU_ConfigDirectory (cert_dir); + + /* Been there done that */ + prior++; + + if(password) { + PK11_SetPasswordFunc(pk11_password_hardcode); + } + + /* Must login to FIPS before you do anything else */ + if(PK11_IsFIPS()) { + slotinfo = PK11_GetInternalSlot(); + if(!slotinfo) { + fprintf(stderr, "%s: Unable to get PKCS #11 Internal Slot." + "\n", PROGRAM_NAME); + return -1; + } + if(PK11_Authenticate(slotinfo, PR_FALSE /*loadCerts*/, + NULL /*wincx*/) != SECSuccess) { + fprintf(stderr, "%s: Unable to authenticate to %s.\n", + PROGRAM_NAME, PK11_GetSlotName(slotinfo)); + PK11_FreeSlot(slotinfo); + return -1; + } + PK11_FreeSlot(slotinfo); + } + + /* Make sure there is a password set on the internal key slot */ + slotinfo = PK11_GetInternalKeySlot(); + if(!slotinfo) { + fprintf(stderr, "%s: Unable to get PKCS #11 Internal Key Slot." + "\n", PROGRAM_NAME); + return -1; + } + if(PK11_NeedUserInit(slotinfo)) { + PR_fprintf(errorFD, +"\nWARNING: No password set on internal key database. Most operations will fail." +"\nYou must use Communicator to create a password.\n"); + warningCount++; + } + + /* Make sure we can authenticate to the key slot in FIPS mode */ + if(PK11_IsFIPS()) { + if(PK11_Authenticate(slotinfo, PR_FALSE /*loadCerts*/, + NULL /*wincx*/) != SECSuccess) { + fprintf(stderr, "%s: Unable to authenticate to %s.\n", + PROGRAM_NAME, PK11_GetSlotName(slotinfo)); + PK11_FreeSlot(slotinfo); + return -1; + } + } + PK11_FreeSlot(slotinfo); + } + + return 0; +} + +/* Windows foolishness is now in the secutil lib */ + +/***************************************************************** + * g e t _ d e f a u l t _ c e r t _ d i r + * + * Attempt to locate a certificate directory. + * Failing that, complain that the user needs to + * use the -d(irectory) parameter. + * + */ +char *get_default_cert_dir (void) +{ + char *home; + + char *cd = NULL; + static char db [FNSIZE]; + +#ifdef XP_UNIX + home = getenv ("HOME"); + + if (home && *home) + { + sprintf (db, "%s/.netscape", home); + cd = db; + } +#endif + +#ifdef XP_PC + FILE *fp; + + /* first check the environment override */ + + home = getenv ("JAR_HOME"); + + if (home && *home) + { + sprintf (db, "%s/cert7.db", home); + + if ((fp = fopen (db, "r")) != NULL) + { + fclose (fp); + cd = home; + } + } + + /* try the old navigator directory */ + + if (cd == NULL) + { + home = "c:/Program Files/Netscape/Navigator"; + + sprintf (db, "%s/cert7.db", home); + + if ((fp = fopen (db, "r")) != NULL) + { + fclose (fp); + cd = home; + } + } + + /* Try the current directory, I wonder if this + is really a good idea. Remember, Windows only.. */ + + if (cd == NULL) + { + home = "."; + + sprintf (db, "%s/cert7.db", home); + + if ((fp = fopen (db, "r")) != NULL) + { + fclose (fp); + cd = home; + } + } + +#endif + + if (!cd) + { + PR_fprintf(errorFD, + "You must specify the location of your certificate directory\n"); + PR_fprintf(errorFD, + "with the -d option. Example: -d ~/.netscape in many cases with Unix.\n"); + errorCount++; + exit (ERRX); + } + + return cd; +} + +/************************************************************************ + * g i v e _ h e l p + */ +void give_help (int status) +{ + if (status == SEC_ERROR_UNKNOWN_ISSUER) + { + PR_fprintf(errorFD, + "The Certificate Authority (CA) for this certificate\n"); + PR_fprintf(errorFD, + "does not appear to be in your database. You should contact\n"); + PR_fprintf(errorFD, + "the organization which issued this certificate to obtain\n"); + PR_fprintf(errorFD, "a copy of its CA Certificate.\n"); + } +} + +/************************************************************************** + * + * p r _ f g e t s + * + * fgets implemented with NSPR. + */ +char* +pr_fgets(char *buf, int size, PRFileDesc *file) +{ + int i; + int status; + char c; + + i=0; + while(i < size-1) { + status = PR_Read(file, (void*) &c, 1); + if(status==-1) { + return NULL; + } else if(status==0) { + break; + } + buf[i++] = c; + if(c=='\n') { + break; + } + } + buf[i]='\0'; + + return buf; +} + diff --git a/security/nss/cmd/signtool/verify.c b/security/nss/cmd/signtool/verify.c new file mode 100644 index 000000000..fd80ef737 --- /dev/null +++ b/security/nss/cmd/signtool/verify.c @@ -0,0 +1,382 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "signtool.h" + + +static int jar_cb(int status, JAR *jar, const char *metafile, + char *pathname, char *errortext); +static int verify_global (JAR *jar); + +/************************************************************************* + * + * V e r i f y J a r + */ +int +VerifyJar(char *filename) +{ + FILE *fp; + + int ret; + int status; + int failed = 0; + char *err; + + JAR *jar; + JAR_Context *ctx; + + JAR_Item *it; + + jar = JAR_new(); + + if ((fp = fopen (filename, "r")) == NULL) + { + perror (filename); + exit (ERRX); + } + else + fclose (fp); + + JAR_set_callback (JAR_CB_SIGNAL, jar, jar_cb); + + + status = JAR_pass_archive (jar, jarArchGuess, filename, "some-url"); + + if (status < 0 || jar->valid < 0) + { + failed = 1; + PR_fprintf(outputFD, "\nNOTE -- \"%s\" archive DID NOT PASS crypto verification.\n", filename); + if (status < 0) + { + char *errtext; + + if (status >= JAR_BASE && status <= JAR_BASE_END) + { + errtext = JAR_get_error (status); + } + else + { + errtext = SECU_ErrorString ((int16) PORT_GetError()); + } + + PR_fprintf(outputFD, " (reported reason: %s)\n\n", errtext); + + /* corrupt files should not have their contents listed */ + + if (status == JAR_ERR_CORRUPT) + return -1; + } + PR_fprintf(outputFD, + "entries shown below will have their digests checked only.\n"); + jar->valid = 0; + } + else + PR_fprintf(outputFD, + "archive \"%s\" has passed crypto verification.\n", filename); + + if (verify_global (jar)) + failed = 1; + + PR_fprintf(outputFD, "\n"); + PR_fprintf(outputFD, "%16s %s\n", "status", "path"); + PR_fprintf(outputFD, "%16s %s\n", "------------", "-------------------"); + + ctx = JAR_find (jar, NULL, jarTypeMF); + + while (JAR_find_next (ctx, &it) >= 0) + { + if (it && it->pathname) + { + rm_dash_r(TMP_OUTPUT); + ret = JAR_verified_extract (jar, it->pathname, TMP_OUTPUT); + /* if (ret < 0) printf ("error %d on %s\n", ret, it->pathname); */ + if (ret < 0) failed = 1; + + if (ret == JAR_ERR_PNF) + err = "NOT PRESENT"; + else if (ret == JAR_ERR_HASH) + err = "HASH FAILED"; + else + err = "NOT VERIFIED"; + + PR_fprintf(outputFD, "%16s %s\n", + ret >= 0 ? "verified" : err, it->pathname); + + if (ret != 0 && ret != JAR_ERR_PNF && ret != JAR_ERR_HASH) + PR_fprintf(outputFD, " (reason: %s)\n", JAR_get_error (ret)); + } + } + + JAR_find_end (ctx); + + if (status < 0 || jar->valid < 0) + { + failed = 1; + PR_fprintf(outputFD, + "\nNOTE -- \"%s\" archive DID NOT PASS crypto verification.\n", filename); + give_help (status); + } + + JAR_destroy (jar); + + if (failed) + return -1; + return 0; +} + +/*************************************************************************** + * + * v e r i f y _ g l o b a l + */ +static int +verify_global (JAR *jar) +{ + FILE *fp; + JAR_Context *ctx; + + char *ext; + + JAR_Item *it; + JAR_Digest *globaldig; + + unsigned int sha1_length, md5_length; + + char buf [BUFSIZ]; + + unsigned char *md5_digest, *sha1_digest; + + int retval = 0; + + ctx = JAR_find (jar, "*", jarTypePhy); + + while (JAR_find_next (ctx, &it) >= 0) { + if (!PORT_Strncmp (it->pathname, "META-INF", 8)) { + for (ext = it->pathname; *ext; ext++); + while (ext > it->pathname && *ext != '.') ext--; + + if(verbosity >= 0) { + if (!PORT_Strcasecmp (ext, ".rsa")) { + PR_fprintf(outputFD, "found a RSA signature file: %s\n", + it->pathname); + } + + if(!PORT_Strcasecmp (ext, ".dsa")) { + PR_fprintf(outputFD, "found a DSA signature file: %s\n", + it->pathname); + } + + if (!PORT_Strcasecmp (ext, ".mf")) { + PR_fprintf(outputFD, + "found a MF master manifest file: %s\n", it->pathname); + } + } + + if (!PORT_Strcasecmp (ext, ".sf")) { + if(verbosity >= 0) { + PR_fprintf(outputFD, + "found a SF signature manifest file: %s\n", it->pathname); + } + + rm_dash_r(TMP_OUTPUT); + if (JAR_extract (jar, it->pathname, TMP_OUTPUT) < 0) { + PR_fprintf(errorFD, "%s: error extracting %s\n", PROGRAM_NAME, + it->pathname); + errorCount++; + retval = -1; + continue; + } + + md5_digest = NULL; + sha1_digest = NULL; + + if ((fp = fopen (TMP_OUTPUT, "rb")) != NULL) { + while (fgets (buf, BUFSIZ, fp)) { + char *s; + + if (*buf == 0 || *buf == '\n' || *buf == '\r') break; + + for (s = buf; *s && *s != '\n' && *s != '\r'; s++); + *s = 0; + + if (!PORT_Strncmp (buf, "MD5-Digest: ", 12)) { + md5_digest = ATOB_AsciiToData (buf + 12, &md5_length); + } + + if (!PORT_Strncmp (buf, "SHA1-Digest: ", 13)) { + sha1_digest = ATOB_AsciiToData (buf + 13, &sha1_length); + } + + if (!PORT_Strncmp (buf, "SHA-Digest: ", 12)) { + sha1_digest = ATOB_AsciiToData (buf + 12, &sha1_length); + } + } + + globaldig = jar->globalmeta; + + if (globaldig && md5_digest) { + if(verbosity >= 0) { + PR_fprintf(outputFD, + " md5 digest on global metainfo: %s\n", + PORT_Memcmp (md5_digest, globaldig->md5, MD5_LENGTH) ? + "no match" : "match"); + } + } + + if (globaldig && sha1_digest) { + if(verbosity >= 0) { + PR_fprintf(outputFD, + " sha digest on global metainfo: %s\n", + PORT_Memcmp(sha1_digest, globaldig->sha1, + SHA1_LENGTH) ? "no match" : "match"); + } + } + + if (globaldig == NULL) { + if(verbosity >= 0) { + PR_fprintf(outputFD, + "global metadigest is not available, strange.\n"); + } + } + + fclose (fp); + } + } + } + } + + JAR_find_end (ctx); + + return retval; +} + +/************************************************************************ + * + * J a r W h o + */ +int +JarWho(char *filename) + { + FILE *fp; + + JAR *jar; + JAR_Context *ctx; + + int status; + int retval = 0; + + JAR_Item *it; + JAR_Cert *fing; + + CERTCertificate *cert, *prev = NULL; + + jar = JAR_new(); + + if ((fp = fopen (filename, "r")) == NULL) + { + perror (filename); + exit (ERRX); + } + else + fclose (fp); + + status = JAR_pass_archive (jar, jarArchGuess, filename, "some-url"); + + if (status < 0 || jar->valid < 0) + { + PR_fprintf(outputFD, + "NOTE -- \"%s\" archive DID NOT PASS crypto verification.\n", filename); + retval = -1; + if (jar->valid < 0 || status != -1) + { + char *errtext; + + if (status >= JAR_BASE && status <= JAR_BASE_END) + { + errtext = JAR_get_error (status); + } + else + { + errtext = SECU_ErrorString ((int16) PORT_GetError()); + } + + PR_fprintf(outputFD, " (reported reason: %s)\n\n", errtext); + } + } + + PR_fprintf(outputFD, "\nSigner information:\n\n"); + + ctx = JAR_find (jar, NULL, jarTypeSign); + + while (JAR_find_next (ctx, &it) >= 0) + { + fing = (JAR_Cert *) it->data; + cert = fing->cert; + + if (cert) + { + if (prev == cert) + break; + + if (cert->nickname) + PR_fprintf(outputFD, "nickname: %s\n", cert->nickname); + if (cert->subjectName) + PR_fprintf(outputFD, "subject name: %s\n", cert->subjectName); + if (cert->issuerName) + PR_fprintf(outputFD, "issuer name: %s\n", cert->issuerName); + } + else + { + PR_fprintf(outputFD, "no certificate could be found\n"); + retval = -1; + } + + prev = cert; + } + + JAR_find_end (ctx); + + JAR_destroy (jar); + return retval; +} + +/************************************************************************ + * j a r _ c b + */ +static int jar_cb(int status, JAR *jar, const char *metafile, + char *pathname, char *errortext) +{ + PR_fprintf(errorFD, "error %d: %s IN FILE %s\n", status, errortext, pathname); + errorCount++; + return 0; +} + diff --git a/security/nss/cmd/signtool/zip.c b/security/nss/cmd/signtool/zip.c new file mode 100644 index 000000000..62e885137 --- /dev/null +++ b/security/nss/cmd/signtool/zip.c @@ -0,0 +1,678 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "signtool.h" +#include "zip.h" +#include "zlib.h" +#include "prmem.h" + +static void inttox (int in, char *out); +static void longtox (long in, char *out); + +/**************************************************************** + * + * J z i p O p e n + * + * Opens a new ZIP file and creates a new ZIPfile structure to + * control the process of installing files into a zip. + */ +ZIPfile* +JzipOpen(char *filename, char *comment) +{ + ZIPfile *zipfile; + PRExplodedTime prtime; + + zipfile = PORT_ZAlloc(sizeof(ZIPfile)); + if(!zipfile) out_of_memory(); + + /* Construct time and date */ + PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &prtime); + zipfile->date = ((prtime.tm_year-1980) << 9) | + ((prtime.tm_month+1) << 5) | + prtime.tm_mday; + zipfile->time = (prtime.tm_hour<<11) | + (prtime.tm_min<<5) | + (prtime.tm_sec&0x3f); + + if (filename && + (zipfile->fp = PR_Open(filename, + PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 0777)) == NULL) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "%s: can't open output jar, %s.%s\n", PROGRAM_NAME, + filename, nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit (ERRX); + } + + zipfile->list = NULL; + if(filename) { + zipfile->filename = PORT_ZAlloc(strlen(filename)+1); + if(!zipfile->filename) out_of_memory(); + PORT_Strcpy(zipfile->filename, filename); + } + if(comment) { + zipfile->comment = PORT_ZAlloc(strlen(comment)+1); + if(!zipfile->comment) out_of_memory(); + PORT_Strcpy(zipfile->comment, comment); + } + + return zipfile; +} + +static +void* +my_alloc_func(void* opaque, uInt items, uInt size) +{ + return PORT_Alloc(items*size); +} + +static +void +my_free_func(void* opaque, void* address) +{ + PORT_Free(address); +} + +static +void +handle_zerror(int err, char *msg) +{ + if(!msg) { + msg = ""; + } + + errorCount++; /* unless Z_OK...see below */ + + switch(err) { + case Z_OK: + PR_fprintf(errorFD, "No error: %s\n", msg); + errorCount--; /* this was incremented above */ + break; + case Z_MEM_ERROR: + PR_fprintf(errorFD, "Deflation ran out of memory: %s\n", msg); + break; + case Z_STREAM_ERROR: + PR_fprintf(errorFD, "Invalid compression level: %s\n", msg); + break; + case Z_VERSION_ERROR: + PR_fprintf(errorFD, "Incompatible compression library version: %s\n", msg); + break; + case Z_DATA_ERROR: + PR_fprintf(errorFD, "Compression data error: %s\n", msg); + break; + default: + PR_fprintf(errorFD, "Unknown error in compression library: %s\n", msg); + break; + } +} + + +/**************************************************************** + * + * J z i p A d d + * + * Adds a new file into a ZIP file. The ZIP file must have already + * been opened with JzipOpen. + */ +int +JzipAdd(char *fullname, char *filename, ZIPfile *zipfile, int compression_level) +{ + ZIPentry *entry; + PRFileDesc *readfp; + PRFileDesc *zipfp; + int num; + Bytef inbuf[BUFSIZ], outbuf[BUFSIZ]; + unsigned long crc; + z_stream zstream; + int err; + unsigned long local_size_pos; + int deflate_percent; + + + if( !fullname || !filename || !zipfile) { + return -1; + } + + zipfp = zipfile->fp; + + + if( (readfp = PR_Open(fullname, PR_RDONLY, 0777)) == NULL) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "%s: %s\n", fullname, nsprErr ? nsprErr : ""); + errorCount++; + if(nsprErr) PR_Free(nsprErr); + exit(ERRX); + } + + /* + * Make sure the input file is not the output file. + * Add a few bytes to the end of the JAR file and see if the input file + * twitches + */ + { + PRInt32 endOfJar; + PRInt32 inputSize; + PRBool isSame; + + inputSize = PR_Available(readfp); + + endOfJar = PR_Seek(zipfp, 0L, PR_SEEK_CUR); + + if(PR_Write(zipfp, "abcde", 5) < 5) { + char *nsprErr; + + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing to zip file: %s\n", + nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + + isSame = (PR_Available(readfp) != inputSize); + + PR_Seek(zipfp, endOfJar, PR_SEEK_SET); + + if(isSame) { + /* It's the same file! Forget it! */ + PR_Close(readfp); + return 0; + } + } + + if(verbosity >= 0) { + PR_fprintf(outputFD, "adding %s to %s...", fullname, zipfile->filename); + } + + entry = PORT_ZAlloc(sizeof(ZIPentry)); + if(!entry) out_of_memory(); + + entry->filename = PORT_Strdup(filename); + entry->comment = NULL; + + /* Set up local file header */ + longtox(LSIG, entry->local.signature); + inttox(strlen(filename), entry->local.filename_len); + inttox(zipfile->time, entry->local.time); + inttox(zipfile->date, entry->local.date); + inttox(Z_DEFLATED, entry->local.method); + + /* Set up central directory entry */ + longtox(CSIG, entry->central.signature); + inttox(strlen(filename), entry->central.filename_len); + if(entry->comment) { + inttox(strlen(entry->comment), entry->central.commentfield_len); + } + longtox(PR_Seek(zipfile->fp, 0, PR_SEEK_CUR), + entry->central.localhdr_offset); + inttox(zipfile->time, entry->central.time); + inttox(zipfile->date, entry->central.date); + inttox(Z_DEFLATED, entry->central.method); + + /* Compute crc. Too bad we have to process the whole file to do this*/ + crc = crc32(0L, NULL, 0); + while( (num = PR_Read(readfp, inbuf, BUFSIZ)) > 0) { + crc = crc32(crc, inbuf, num); + } + PR_Seek(readfp, 0L, PR_SEEK_SET); + + /* Store CRC */ + longtox(crc, entry->local.crc32); + longtox(crc, entry->central.crc32); + + /* Stick this entry onto the end of the list */ + entry->next = NULL; + if( zipfile->list == NULL ) { + /* First entry */ + zipfile->list = entry; + } else { + ZIPentry *pe; + + pe = zipfile->list; + while(pe->next != NULL) { + pe = pe->next; + } + pe->next = entry; + } + + /* + * Start writing stuff out + */ + + local_size_pos = PR_Seek(zipfp, 0, PR_SEEK_CUR) + 18; + /* File header */ + if(PR_Write(zipfp, &entry->local, sizeof(struct ZipLocal)) + < sizeof(struct ZipLocal)) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + + /* File Name */ + if( PR_Write(zipfp, filename, strlen(filename)) < strlen(filename)) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + + /* + * File data + */ + /* Initialize zstream */ + zstream.zalloc = my_alloc_func; + zstream.zfree = my_free_func; + zstream.opaque = NULL; + zstream.next_in = inbuf; + zstream.avail_in = BUFSIZ; + zstream.next_out = outbuf; + zstream.avail_out = BUFSIZ; + /* Setting the windowBits to -MAX_WBITS is an undocumented feature of + * zlib (see deflate.c in zlib). It is the same thing that Java does + * when you specify the nowrap option for deflation in java.util.zip. + * It causes zlib to leave out its headers and footers, which don't + * work in PKZIP files. + */ + err = deflateInit2(&zstream, compression_level, Z_DEFLATED, + -MAX_WBITS, 8 /*default*/, Z_DEFAULT_STRATEGY); + if(err != Z_OK) { + handle_zerror(err, zstream.msg); + exit(ERRX); + } + + while( (zstream.avail_in = PR_Read(readfp, inbuf, BUFSIZ)) > 0) { + zstream.next_in = inbuf; + /* Process this chunk of data */ + while(zstream.avail_in > 0) { + err = deflate(&zstream, Z_NO_FLUSH); + if(err != Z_OK) { + handle_zerror(err, zstream.msg); + exit(ERRX); + } + if(zstream.avail_out <= 0) { + if( PR_Write(zipfp, outbuf, BUFSIZ) < BUFSIZ) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", + nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + zstream.next_out = outbuf; + zstream.avail_out = BUFSIZ; + } + } + } + + /* Now flush everything */ + while(1) { + err = deflate(&zstream, Z_FINISH); + if(err == Z_STREAM_END) { + break; + } else if(err == Z_OK) { + /* output buffer full, repeat */ + } else { + handle_zerror(err, zstream.msg); + exit(ERRX); + } + if( PR_Write(zipfp, outbuf, BUFSIZ) < BUFSIZ) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", + nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + zstream.avail_out = BUFSIZ; + zstream.next_out = outbuf; + } + + /* If there's any output left, write it out. */ + if(zstream.next_out != outbuf) { + if( PR_Write(zipfp, outbuf, zstream.next_out-outbuf) < + zstream.next_out-outbuf) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", + nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + zstream.avail_out = BUFSIZ; + zstream.next_out = outbuf; + } + + /* Now that we know the compressed size, write this to the headers */ + longtox(zstream.total_in, entry->local.orglen); + longtox(zstream.total_out, entry->local.size); + if(PR_Seek(zipfp, local_size_pos, PR_SEEK_SET) == -1) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Accessing zip file: %s\n", nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + if( PR_Write(zipfp, entry->local.size, 8) != 8) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + if(PR_Seek(zipfp, 0L, PR_SEEK_END) == -1) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Accessing zip file: %s\n", nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + longtox(zstream.total_in, entry->central.orglen); + longtox(zstream.total_out, entry->central.size); + + /* Close out the deflation operation */ + err = deflateEnd(&zstream); + if(err != Z_OK) { + handle_zerror(err, zstream.msg); + exit(ERRX); + } + + PR_Close(readfp); + + if((zstream.total_in > zstream.total_out) && (zstream.total_in > 0)) { + deflate_percent = (int) ( (zstream.total_in-zstream.total_out)*100 / + zstream.total_in ); + } else { + deflate_percent = 0; + } + if(verbosity >= 0) { + PR_fprintf(outputFD, "(deflated %d%%)\n", deflate_percent); + } + + return 0; +} + +/******************************************************************** + * J z i p C l o s e + * + * Finishes the ZipFile. ALSO DELETES THE ZIPFILE STRUCTURE PASSED IN!! + */ +int +JzipClose(ZIPfile *zipfile) +{ + ZIPentry *pe, *dead; + PRFileDesc *zipfp; + struct ZipEnd zipend; + unsigned int entrycount = 0; + + if(!zipfile) { + return -1; + } + + if(!zipfile->filename) { + /* bogus */ + return 0; + } + + zipfp = zipfile->fp; + zipfile->central_start = PR_Seek(zipfp, 0L, PR_SEEK_CUR); + + /* Write out all the central directories */ + pe = zipfile->list; + while(pe) { + entrycount++; + + /* Write central directory info */ + if( PR_Write(zipfp, &pe->central, sizeof(struct ZipCentral)) + < sizeof(struct ZipCentral)) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", + nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + + /* Write filename */ + if( PR_Write(zipfp, pe->filename, strlen(pe->filename)) + < strlen(pe->filename)) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", + nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + + /* Write file comment */ + if(pe->comment) { + if( PR_Write(zipfp, pe->comment, strlen(pe->comment)) + < strlen(pe->comment)) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", + nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + } + + /* Delete the structure */ + dead = pe; + pe = pe->next; + if(dead->filename) { + PORT_Free(dead->filename); + } + if(dead->comment) { + PORT_Free(dead->comment); + } + PORT_Free(dead); + } + zipfile->central_end = PR_Seek(zipfile->fp, 0L, PR_SEEK_CUR); + + /* Create the ZipEnd structure */ + PORT_Memset(&zipend, 0, sizeof(zipend)); + longtox(ESIG, zipend.signature); + inttox(entrycount, zipend.total_entries_disk); + inttox(entrycount, zipend.total_entries_archive); + longtox(zipfile->central_end-zipfile->central_start, + zipend.central_dir_size); + longtox(zipfile->central_start, zipend.offset_central_dir); + if(zipfile->comment) { + inttox(strlen(zipfile->comment), zipend.commentfield_len); + } + + /* Write out ZipEnd xtructure */ + if( PR_Write(zipfp, &zipend, sizeof(zipend)) < sizeof(zipend)) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + + /* Write out Zipfile comment */ + if(zipfile->comment) { + if( PR_Write(zipfp, zipfile->comment, strlen(zipfile->comment)) + < strlen(zipfile->comment)) { + char *nsprErr; + if(PR_GetErrorTextLength()) { + nsprErr = PR_Malloc(PR_GetErrorTextLength()); + PR_GetErrorText(nsprErr); + } else { + nsprErr = NULL; + } + PR_fprintf(errorFD, "Writing zip data: %s\n", + nsprErr ? nsprErr : ""); + if(nsprErr) PR_Free(nsprErr); + errorCount++; + exit(ERRX); + } + } + + PR_Close(zipfp); + + /* Free the memory of the zipfile structure */ + if(zipfile->filename) { + PORT_Free(zipfile->filename); + } + if(zipfile->comment) { + PORT_Free(zipfile->comment); + } + PORT_Free(zipfile); + + return 0; +} + +/********************************************** + * i n t t o x + * + * Converts a two byte ugly endianed integer + * to our platform's integer. + * + */ + +static void inttox (int in, char *out) +{ + out [0] = (in & 0xFF); + out [1] = (in & 0xFF00) >> 8; +} + +/********************************************* + * l o n g t o x + * + * Converts a four byte ugly endianed integer + * to our platform's integer. + * + */ + +static void longtox (long in, char *out) +{ + out [0] = (in & 0xFF); + out [1] = (in & 0xFF00) >> 8; + out [2] = (in & 0xFF0000) >> 16; + out [3] = (in & 0xFF000000) >> 24; +} + diff --git a/security/nss/cmd/signtool/zip.h b/security/nss/cmd/signtool/zip.h new file mode 100644 index 000000000..08512f3c4 --- /dev/null +++ b/security/nss/cmd/signtool/zip.h @@ -0,0 +1,100 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* zip.h + * Structures and functions for creating ZIP archives. + */ +#ifndef ZIP_H +#define ZIP_H + +/* For general information on ZIP formats, you can look at jarfile.h + * in ns/security/lib/jar. Or look it up on the web... + */ + +/* One entry in a ZIPfile. This corresponds to one file in the archive. + * We have to save this information because first all the files go into + * the archive with local headers; then at the end of the file we have to + * put the central directory entries for each file. + */ +typedef struct ZIPentry_s { + struct ZipLocal local; /* local header info */ + struct ZipCentral central; /* central directory info */ + char *filename; /* name of file */ + char *comment; /* comment for this file -- optional */ + + struct ZIPentry_s *next; +} ZIPentry; + +/* This structure contains the necessary data for putting a ZIP file + * together. Has some overall information and a list of ZIPentrys. + */ +typedef struct ZIPfile_s { + char *filename; /* ZIP file name */ + char *comment; /* ZIP file comment -- may be NULL */ + PRFileDesc *fp; /* ZIP file pointer */ + ZIPentry *list; /* one entry for each file in the archive */ + unsigned int time; /* the GMT time of creation, in DOS format */ + unsigned int date; /* the GMT date of creation, in DOS format */ + unsigned long central_start; /* starting offset of central directory */ + unsigned long central_end; /*index right after the last byte of central*/ +} ZIPfile; + + +/* Open a new ZIP file. Takes the name of the zip file and an optional + * comment to be included in the file. Returns a new ZIPfile structure + * which is used by JzipAdd and JzipClose + */ +ZIPfile* JzipOpen(char *filename, char *comment); + +/* Add a file to a ZIP archive. Fullname is the path relative to the + * current directory. Filename is what the name will be stored as in the + * archive, and thus what it will be restored as. zipfile is a structure + * returned from a previous call to JzipOpen. + * + * Non-zero return code means error (although usually the function will + * call exit() rather than return an error--gotta fix this). + */ +int JzipAdd(char *fullname, char *filename, ZIPfile *zipfile, + int compression_level); + +/* Finalize a ZIP archive. Adds all the footer information to the end of + * the file and closes it. Also DELETES THE ZIPFILE STRUCTURE that was + * passed in. So you never have to allocate or free a ZIPfile yourself. + * + * Non-zero return code means error (although usually the function will + * call exit() rather than return an error--gotta fix this). + */ +int JzipClose (ZIPfile *zipfile); + + +#endif /* ZIP_H */ diff --git a/security/nss/cmd/signver/Makefile b/security/nss/cmd/signver/Makefile new file mode 100644 index 000000000..e4a3a6069 --- /dev/null +++ b/security/nss/cmd/signver/Makefile @@ -0,0 +1,71 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +include ../platrules.mk diff --git a/security/nss/cmd/signver/examples/1/form.pl b/security/nss/cmd/signver/examples/1/form.pl new file mode 100755 index 000000000..2034bf728 --- /dev/null +++ b/security/nss/cmd/signver/examples/1/form.pl @@ -0,0 +1,50 @@ +#! /usr/bin/perl +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + + +print "Content-type: text/html\n\n"; +print "<B>Server Name:</B> ", $ENV{'SERVER_NAME'}, "<BR>", "\n"; +print "<B>Server Port:</B> ", $ENV{'SERVER_PORT'}, "<BR>", "\n"; +print "<B>Server Software:</B> ", $ENV{'SERVER_SOFTWARE'}, "<BR>", "\n"; +print "<B>Server Protocol:</B> ", $ENV{'SERVER_PROTOCOL'}, "<BR>", "\n"; +print "<B>CGI Revision:</B> ", $ENV{'GATEWAY_INTERFACE'}, "<BR>", "\n"; +print "<B>Browser:</B> ", $ENV{'HTTP_USER_AGENT'}, "<BR>", "\n"; +print "<B>Remote Address:</B> ", $ENV{'REMOTE_ADDR'}, "<BR>", "\n"; +print "<B>Remote Host:</B> ", $ENV{'REMOTE_HOST'}, "<BR>", "\n"; +print "<B>Remote User:</B> ", $ENV{'REMOTE_USER'}, "<BR>", "\n"; +print "You typed:\n"; + +while( $_ = <STDIN>) { + print "$_"; +} + diff --git a/security/nss/cmd/signver/examples/1/signedForm.html b/security/nss/cmd/signver/examples/1/signedForm.html new file mode 100644 index 000000000..1444a1775 --- /dev/null +++ b/security/nss/cmd/signver/examples/1/signedForm.html @@ -0,0 +1,84 @@ +<html> +<!-- + - The contents of this file are subject to the Mozilla Public + - License Version 1.1 (the "License"); you may not use this file + - except in compliance with the License. You may obtain a copy of + - the License at http://www.mozilla.org/MPL/ + - + - Software distributed under the License is distributed on an "AS + - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + - implied. See the License for the specific language governing + - rights and limitations under 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. + --> +<head> +<title>Form to sign</title> +<script language="javascript"> +<!-- +function submitSigned(form){ + var signature = ""; + var dataToSign = ""; + var i; + + form.action='signedForm.pl'; + for (i = 0; i < form.length; i++) + if (form.elements[i].type == "text") + dataToSign += form.elements[i].value; + + // alert("Data to sign:\n" + dataToSign); + signature = crypto.signText(dataToSign, "ask"); + /* alert("You cannot see this alert"); + alert("Data signature:\n" + signature); */ + + if (signature != "error:userCancel") { + for (i = 0; i < form.length; i++) { + if (form.elements[i].type == "hidden") { + if (form.elements[i].name == "dataToSign") + form.elements[i].value = dataToSign; + if (form.elements[i].name == "dataSignature") + form.elements[i].value = signature; + } + } + form.submit(); + } +} +//--> +</script> +</head> + +<body> +<form method=post Action="form.pl"> +<input type=hidden size=30 name=dataSignature> +<input type=hidden size=30 name=dataToSign> +<input type=text size=30 name=p> +<BR> +<input type=text size=30 name=q> +<BR> +<input type=text size=30 name=r> +<BR> +<input type=submit value="Submit Data"> +<input type=button value="Sign and Submit Data" onclick=submitSigned(this.form)> +<input type=reset value=Reset> +</form> +</body> +</html> diff --git a/security/nss/cmd/signver/examples/1/signedForm.nt.html b/security/nss/cmd/signver/examples/1/signedForm.nt.html new file mode 100644 index 000000000..5487739ce --- /dev/null +++ b/security/nss/cmd/signver/examples/1/signedForm.nt.html @@ -0,0 +1,84 @@ +<html> +<!-- + - The contents of this file are subject to the Mozilla Public + - License Version 1.1 (the "License"); you may not use this file + - except in compliance with the License. You may obtain a copy of + - the License at http://www.mozilla.org/MPL/ + - + - Software distributed under the License is distributed on an "AS + - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + - implied. See the License for the specific language governing + - rights and limitations under 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. + --> +<head> +<title>Form to sign</title> +<script language="javascript"> +<!-- +function submitSigned(form){ + var signature = ""; + var dataToSign = ""; + var i; + + form.action='cgi-bin/signedForm.pl'; + for (i = 0; i < form.length; i++) + if (form.elements[i].type == "text") + dataToSign += form.elements[i].value; + + // alert("Data to sign:\n" + dataToSign); + signature = crypto.signText(dataToSign, "ask"); + /* alert("You cannot see this alert"); + alert("Data signature:\n" + signature); */ + + if (signature != "error:userCancel") { + for (i = 0; i < form.length; i++) { + if (form.elements[i].type == "hidden") { + if (form.elements[i].name == "dataToSign") + form.elements[i].value = dataToSign; + if (form.elements[i].name == "dataSignature") + form.elements[i].value = signature; + } + } + form.submit(); + } +} +//--> +</script> +</head> + +<body> +<form method=post Action="cgi-bin/form.pl"> +<input type=hidden size=30 name=dataSignature> +<input type=hidden size=30 name=dataToSign> +<input type=text size=30 name=p> +<BR> +<input type=text size=30 name=q> +<BR> +<input type=text size=30 name=r> +<BR> +<input type=submit value="Submit Data"> +<input type=button value="Sign and Submit Data" onclick=submitSigned(this.form)> +<input type=reset value=Reset> +</form> +</body> +</html> diff --git a/security/nss/cmd/signver/examples/1/signedForm.pl b/security/nss/cmd/signver/examples/1/signedForm.pl new file mode 100755 index 000000000..3c2cd0ed3 --- /dev/null +++ b/security/nss/cmd/signver/examples/1/signedForm.pl @@ -0,0 +1,88 @@ +#! /usr/bin/perl +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + + + +sub decode { + read (STDIN, $buffer, $ENV{'CONTENT_LENGTH'}); + @pairs = split(/&/, $buffer); + foreach $pair (@pairs) + { + ($name, $value) = split(/=/, $pair); + $value =~tr/+/ /; + $value =~ s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg; + $FORM{$name} = $value; +# print "name=$name value=$value<BR>\n"; + } +} + +print "Content-type: text/html\n\n"; + +&decode(); + +$dataSignature = $FORM{'dataSignature'}; +$dataToSign = $FORM{'dataToSign'}; + +unlink("signature"); +open(FILE1,">signature") || die("Cannot open file for writing\n"); + +print FILE1 "$dataSignature"; + +close(FILE1); + + +unlink("data"); +open(FILE2,">data") || die("Cannot open file for writing\n"); + +print FILE2 "$dataToSign"; + +close(FILE2); + + +print "<BR><B>Signed Data:</B><BR>", "$dataToSign", "<BR>"; + +print "<BR><b>Verification Info:</b><BR>"; + +$verInfo = `./signver -D . -s signature -d data -v`; +print "<font color=red><b>$verInfo</b></font><BR>"; + +print "<BR><B>Signature Data:</B><BR>", "$dataSignature", "<BR>"; + +print "<BR><b>Signature Info:</b><BR>"; + +foreach $line (`./signver -s signature -A`) { + print "$line<BR>\n"; +} + +print "<b>End of Info</b><BR>"; + diff --git a/security/nss/cmd/signver/manifest.mn b/security/nss/cmd/signver/manifest.mn new file mode 100644 index 000000000..9efdaad29 --- /dev/null +++ b/security/nss/cmd/signver/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +MODULE = nss + +CSRCS = signver.c \ + pk7print.c \ + $(NULL) + +REQUIRES = dbm seccmd + +PROGRAM = signver + +PACKAGE_FILES = README.txt signedForm.html signedForm.pl form.pl +ifeq ($(subst /,_,$(shell uname -s)),WINNT) +PACKAGE_FILES += signedForm.nt.pl signver.exe +else +PACKAGE_FILES += signver +endif + +ARCHIVE_NAME = signver + +USE_STATIC_LIBS = 1 diff --git a/security/nss/cmd/signver/pk7print.c b/security/nss/cmd/signver/pk7print.c new file mode 100644 index 000000000..94d8e8f36 --- /dev/null +++ b/security/nss/cmd/signver/pk7print.c @@ -0,0 +1,922 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* +** secutil.c - various functions used by security stuff +** +*/ + +/* pkcs #7 -related functions */ + + +#include "secutil.h" +#include "secpkcs7.h" +#include "secoid.h" +#include <sys/stat.h> +#include <stdarg.h> + +#ifdef XP_UNIX +#include <unistd.h> +#endif + +/* for SEC_TraverseNames */ +#include "cert.h" +#include "prtypes.h" +#include "prtime.h" + +#include "prlong.h" +#include "secmod.h" +#include "pk11func.h" +#include "prerror.h" + + + + +/* +** PKCS7 Support +*/ + +/* forward declaration */ +int +sv_PrintPKCS7ContentInfo(FILE *, SEC_PKCS7ContentInfo *, char *); + + +void +sv_PrintAsHex(FILE *out, SECItem *data, char *m) +{ + unsigned i; + + if (m) fprintf(out, m); + + for (i = 0; i < data->len; i++) { + if (i < data->len - 1) { + fprintf(out, "%02x:", data->data[i]); + } else { + fprintf(out, "%02x\n", data->data[i]); + break; + } + } +} + +void +sv_PrintInteger(FILE *out, SECItem *i, char *m) +{ + int iv; + + if (i->len > 4) { + sv_PrintAsHex(out, i, m); + } else { + iv = DER_GetInteger(i); + fprintf(out, "%s%d (0x%x)\n", m, iv, iv); + } +} + + +int +sv_PrintUTCTime(FILE *out, SECItem *t, char *m) +{ + PRExplodedTime printableTime; + int64 time; + char *timeString; + int rv; + + rv = DER_UTCTimeToTime(&time, t); + if (rv) return rv; + + /* Converse to local time */ + PR_ExplodeTime(time, PR_GMTParameters, &printableTime); + + timeString = (char *)PORT_Alloc(100); + + if ( timeString ) { + PR_FormatTime( timeString, 100, "%a %b %d %H:%M:%S %Y", &printableTime ); + fprintf(out, "%s%s\n", m, timeString); + PORT_Free(timeString); + return 0; + } + return SECFailure; +} + + +int +sv_PrintValidity(FILE *out, CERTValidity *v, char *m) +{ + int rv; + + fprintf(out, m); + rv = sv_PrintUTCTime(out, &v->notBefore, "notBefore="); + if (rv) return rv; + fprintf(out, m); + sv_PrintUTCTime(out, &v->notAfter, "notAfter="); + return rv; +} + +void +sv_PrintObjectID(FILE *out, SECItem *oid, char *m) +{ + const char *name; + SECOidData *oiddata; + + oiddata = SECOID_FindOID(oid); + if (oiddata == NULL) { + sv_PrintAsHex(out, oid, m); + return; + } + name = oiddata->desc; + + if (m != NULL) + fprintf(out, "%s", m); + fprintf(out, "%s\n", name); +} + +void +sv_PrintAlgorithmID(FILE *out, SECAlgorithmID *a, char *m) +{ + sv_PrintObjectID(out, &a->algorithm, m); + + if ((a->parameters.len != 2) || + (PORT_Memcmp(a->parameters.data, "\005\000", 2) != 0)) { + /* Print args to algorithm */ + sv_PrintAsHex(out, &a->parameters, "Args="); + } +} + +void +sv_PrintAttribute(FILE *out, SEC_PKCS7Attribute *attr, char *m) +{ + SECItem *value; + int i; + char om[100]; + + fprintf(out, m); + + /* + * XXX Make this smarter; look at the type field and then decode + * and print the value(s) appropriately! + */ + sv_PrintObjectID(out, &(attr->type), "type="); + if (attr->values != NULL) { + i = 0; + while ((value = attr->values[i]) != NULL) { + sprintf(om, "%svalue[%d]=%s", m, i++, attr->encoded ? "(encoded)" : ""); + if (attr->encoded || attr->typeTag == NULL) { + sv_PrintAsHex(out, value, om); + } else { + switch (attr->typeTag->offset) { + default: + sv_PrintAsHex(out, value, om); + break; + case SEC_OID_PKCS9_CONTENT_TYPE: + sv_PrintObjectID(out, value, om); + break; + case SEC_OID_PKCS9_SIGNING_TIME: + sv_PrintUTCTime(out, value, om); + break; + } + } + } + } +} + +void +sv_PrintName(FILE *out, CERTName *name, char *msg) +{ + char *str; + + str = CERT_NameToAscii(name); + fprintf(out, "%s%s\n", msg, str); +} + + +#if 0 +/* +** secu_PrintPKCS7EncContent +** Prints a SEC_PKCS7EncryptedContentInfo (without decrypting it) +*/ +void +secu_PrintPKCS7EncContent(FILE *out, SEC_PKCS7EncryptedContentInfo *src, + char *m, int level) +{ + if (src->contentTypeTag == NULL) + src->contentTypeTag = SECOID_FindOID(&(src->contentType)); + + secu_Indent(out, level); + fprintf(out, "%s:\n", m); + secu_Indent(out, level + 1); + fprintf(out, "Content Type: %s\n", + (src->contentTypeTag != NULL) ? src->contentTypeTag->desc + : "Unknown"); + sv_PrintAlgorithmID(out, &(src->contentEncAlg), + "Content Encryption Algorithm"); + sv_PrintAsHex(out, &(src->encContent), + "Encrypted Content", level+1); +} + +/* +** secu_PrintRecipientInfo +** Prints a PKCS7RecipientInfo type +*/ +void +secu_PrintRecipientInfo(FILE *out, SEC_PKCS7RecipientInfo *info, char *m, + int level) +{ + secu_Indent(out, level); fprintf(out, "%s:\n", m); + sv_PrintInteger(out, &(info->version), "Version"); + + sv_PrintName(out, &(info->issuerAndSN->issuer), "Issuer"); + sv_PrintInteger(out, &(info->issuerAndSN->serialNumber), + "Serial Number"); + + /* Parse and display encrypted key */ + sv_PrintAlgorithmID(out, &(info->keyEncAlg), + "Key Encryption Algorithm"); + sv_PrintAsHex(out, &(info->encKey), "Encrypted Key", level + 1); +} +#endif + +/* +** secu_PrintSignerInfo +** Prints a PKCS7SingerInfo type +*/ +void +sv_PrintSignerInfo(FILE *out, SEC_PKCS7SignerInfo *info, char *m) +{ + SEC_PKCS7Attribute *attr; + int iv; + + fprintf(out, m); + sv_PrintInteger(out, &(info->version), "version="); + + fprintf(out, m); + sv_PrintName(out, &(info->issuerAndSN->issuer), "issuerName="); + fprintf(out, m); + sv_PrintInteger(out, &(info->issuerAndSN->serialNumber), + "serialNumber="); + + fprintf(out, m); + sv_PrintAlgorithmID(out, &(info->digestAlg), "digestAlgorithm="); + + if (info->authAttr != NULL) { + char mm[120]; + + iv = 0; + while (info->authAttr[iv] != NULL) iv++; + fprintf(out, "%sauthenticatedAttributes=%d\n", m, iv); + iv = 0; + while ((attr = info->authAttr[iv]) != NULL) { + sprintf(mm, "%sattribute[%d].", m, iv++); + sv_PrintAttribute(out, attr, mm); + } + } + + /* Parse and display signature */ + fprintf(out, m); + sv_PrintAlgorithmID(out, &(info->digestEncAlg), "digestEncryptionAlgorithm="); + fprintf(out, m); + sv_PrintAsHex(out, &(info->encDigest), "encryptedDigest="); + + if (info->unAuthAttr != NULL) { + char mm[120]; + + iv = 0; + while (info->unAuthAttr[iv] != NULL) iv++; + fprintf(out, "%sunauthenticatedAttributes=%d\n", m, iv); + iv = 0; + while ((attr = info->unAuthAttr[iv]) != NULL) { + sprintf(mm, "%sattribute[%d].", m, iv++); + sv_PrintAttribute(out, attr, mm); + } + } +} + +void +sv_PrintRSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m) +{ + fprintf(out, m); + sv_PrintInteger(out, &pk->u.rsa.modulus, "modulus="); + fprintf(out, m); + sv_PrintInteger(out, &pk->u.rsa.publicExponent, "exponent="); +} + +void +sv_PrintDSAPublicKey(FILE *out, SECKEYPublicKey *pk, char *m) +{ + fprintf(out, m); + sv_PrintInteger(out, &pk->u.dsa.params.prime, "prime="); + fprintf(out, m); + sv_PrintInteger(out, &pk->u.dsa.params.subPrime, "subprime="); + fprintf(out, m); + sv_PrintInteger(out, &pk->u.dsa.params.base, "base="); + fprintf(out, m); + sv_PrintInteger(out, &pk->u.dsa.publicValue, "publicValue="); +} + +int +sv_PrintSubjectPublicKeyInfo(FILE *out, PRArenaPool *arena, + CERTSubjectPublicKeyInfo *i, char *msg) +{ + SECKEYPublicKey *pk; + int rv; + char mm[200]; + + sprintf(mm, "%s.publicKeyAlgorithm=", msg); + sv_PrintAlgorithmID(out, &i->algorithm, mm); + + pk = (SECKEYPublicKey*) PORT_ZAlloc(sizeof(SECKEYPublicKey)); + if (!pk) return PORT_GetError(); + + DER_ConvertBitString(&i->subjectPublicKey); + switch(SECOID_FindOIDTag(&i->algorithm.algorithm)) { + case SEC_OID_PKCS1_RSA_ENCRYPTION: + rv = SEC_ASN1DecodeItem(arena, pk, SECKEY_RSAPublicKeyTemplate, + &i->subjectPublicKey); + if (rv) return rv; + sprintf(mm, "%s.rsaPublicKey.", msg); + sv_PrintRSAPublicKey(out, pk, mm); + break; + case SEC_OID_ANSIX9_DSA_SIGNATURE: + rv = SEC_ASN1DecodeItem(arena, pk, SECKEY_DSAPublicKeyTemplate, + &i->subjectPublicKey); + if (rv) return rv; + sprintf(mm, "%s.dsaPublicKey.", msg); + sv_PrintDSAPublicKey(out, pk, mm); + break; + default: + fprintf(out, "%s=bad SPKI algorithm type\n", msg); + return 0; + } + + return 0; +} + +SECStatus +sv_PrintInvalidDateExten (FILE *out, SECItem *value, char *msg) +{ + SECItem decodedValue; + SECStatus rv; + int64 invalidTime; + char *formattedTime = NULL; + + decodedValue.data = NULL; + rv = SEC_ASN1DecodeItem (NULL, &decodedValue, SEC_GeneralizedTimeTemplate, + value); + if (rv == SECSuccess) { + rv = DER_GeneralizedTimeToTime(&invalidTime, &decodedValue); + if (rv == SECSuccess) { + formattedTime = CERT_GenTime2FormattedAscii(invalidTime, "%a %b %d %H:%M:%S %Y"); + fprintf (out, "%s: %s\n", msg, formattedTime); + PORT_Free (formattedTime); + } + } + PORT_Free (decodedValue.data); + + return (rv); +} + +int +sv_PrintExtensions(FILE *out, CERTCertExtension **extensions, char *msg) +{ + SECOidTag oidTag; + + if (extensions) { + + while ( *extensions ) { + SECItem *tmpitem; + + fprintf(out, "%sname=", msg); + + tmpitem = &(*extensions)->id; + sv_PrintObjectID(out, tmpitem, NULL); + + tmpitem = &(*extensions)->critical; + if ( tmpitem->len ) + fprintf(out, "%scritical=%s\n", msg, + (tmpitem->data && tmpitem->data[0])? "True": "False"); + + oidTag = SECOID_FindOIDTag (&((*extensions)->id)); + + fprintf(out, msg); + tmpitem = &((*extensions)->value); + if (oidTag == SEC_OID_X509_INVALID_DATE) + sv_PrintInvalidDateExten (out, tmpitem,"invalidExt"); + else + sv_PrintAsHex(out,tmpitem, "data="); + + /*fprintf(out, "\n");*/ + extensions++; + } + } + + return 0; +} + +/* callers of this function must make sure that the CERTSignedCrl + from which they are extracting the CERTCrl has been fully-decoded. + Otherwise it will not have the entries even though the CRL may have + some */ +void +sv_PrintCRLInfo(FILE *out, CERTCrl *crl, char *m) +{ + CERTCrlEntry *entry; + int iv; + char om[100]; + + fprintf(out, m); + sv_PrintAlgorithmID(out, &(crl->signatureAlg), "signatureAlgorithm="); + fprintf(out, m); + sv_PrintName(out, &(crl->name), "name="); + fprintf(out, m); + sv_PrintUTCTime(out, &(crl->lastUpdate), "lastUpdate="); + fprintf(out, m); + sv_PrintUTCTime(out, &(crl->nextUpdate), "nextUpdate="); + + if (crl->entries != NULL) { + iv = 0; + while ((entry = crl->entries[iv]) != NULL) { + fprintf(out, "%sentry[%d].", m, iv); + sv_PrintInteger(out, &(entry->serialNumber), "serialNumber="); + fprintf(out, "%sentry[%d].", m, iv); + sv_PrintUTCTime(out, &(entry->revocationDate), "revocationDate="); + sprintf(om, "%sentry[%d].signedCRLEntriesExtensions.", m, iv++); + sv_PrintExtensions(out, entry->extensions, om); + } + } + sprintf(om, "%ssignedCRLEntriesExtensions.", m); + sv_PrintExtensions(out, crl->extensions, om); +} + + +int +sv_PrintCertificate(FILE *out, SECItem *der, char *m, int level) +{ + PRArenaPool *arena = NULL; + CERTCertificate *c; + int rv; + int iv; + char mm[200]; + + /* Decode certificate */ + c = (CERTCertificate*) PORT_ZAlloc(sizeof(CERTCertificate)); + if (!c) return PORT_GetError(); + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!arena) return SEC_ERROR_NO_MEMORY; + + rv = SEC_ASN1DecodeItem(arena, c, CERT_CertificateTemplate, der); + if (rv) { + PORT_FreeArena(arena, PR_FALSE); + return rv; + } + + /* Pretty print it out */ + iv = DER_GetInteger(&c->version); + fprintf(out, "%sversion=%d (0x%x)\n", m, iv + 1, iv); + sprintf(mm, "%sserialNumber=", m); + sv_PrintInteger(out, &c->serialNumber, mm); + sprintf(mm, "%ssignatureAlgorithm=", m); + sv_PrintAlgorithmID(out, &c->signature, mm); + sprintf(mm, "%sissuerName=", m); + sv_PrintName(out, &c->issuer, mm); + sprintf(mm, "%svalidity.", m); + sv_PrintValidity(out, &c->validity, mm); + sprintf(mm, "%ssubject=", m); + sv_PrintName(out, &c->subject, mm); + sprintf(mm, "%ssubjectPublicKeyInfo", m); + rv = sv_PrintSubjectPublicKeyInfo(out, arena, &c->subjectPublicKeyInfo, mm); + if (rv) { + PORT_FreeArena(arena, PR_FALSE); + return rv; + } + sprintf(mm, "%ssignedExtensions.", m); + sv_PrintExtensions(out, c->extensions, mm); + + PORT_FreeArena(arena, PR_FALSE); + return 0; +} + +int +sv_PrintSignedData(FILE *out, SECItem *der, char *m, SECU_PPFunc inner) +{ + PRArenaPool *arena = NULL; + CERTSignedData *sd; + int rv; + + /* Strip off the signature */ + sd = (CERTSignedData*) PORT_ZAlloc(sizeof(CERTSignedData)); + if (!sd) return PORT_GetError(); + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!arena) return SEC_ERROR_NO_MEMORY; + + rv = SEC_ASN1DecodeItem(arena, sd, CERT_SignedDataTemplate, der); + if (rv) { + PORT_FreeArena(arena, PR_FALSE); + return rv; + } + +/* fprintf(out, "%s:\n", m); */ + PORT_Strcat(m, "data."); + + rv = (*inner)(out, &sd->data, m, 0); + if (rv) { + PORT_FreeArena(arena, PR_FALSE); + return rv; + } + + m[PORT_Strlen(m) - 5] = 0; + fprintf(out, m); + sv_PrintAlgorithmID(out, &sd->signatureAlgorithm, "signatureAlgorithm="); + DER_ConvertBitString(&sd->signature); + fprintf(out, m); + sv_PrintAsHex(out, &sd->signature, "signature="); + + PORT_FreeArena(arena, PR_FALSE); + return 0; + +} + + +/* +** secu_PrintPKCS7Signed +** Pretty print a PKCS7 signed data type (up to version 1). +*/ +int +sv_PrintPKCS7Signed(FILE *out, SEC_PKCS7SignedData *src) +{ + SECAlgorithmID *digAlg; /* digest algorithms */ + SECItem *aCert; /* certificate */ + CERTSignedCrl *aCrl; /* certificate revocation list */ + SEC_PKCS7SignerInfo *sigInfo; /* signer information */ + int rv, iv; + char om[120]; + + sv_PrintInteger(out, &(src->version), "pkcs7.version="); + + /* Parse and list digest algorithms (if any) */ + if (src->digestAlgorithms != NULL) { + iv = 0; + while (src->digestAlgorithms[iv] != NULL) + iv++; + fprintf(out, "pkcs7.digestAlgorithmListLength=%d\n", iv); + iv = 0; + while ((digAlg = src->digestAlgorithms[iv]) != NULL) { + sprintf(om, "pkcs7.digestAlgorithm[%d]=", iv++); + sv_PrintAlgorithmID(out, digAlg, om); + } + } + + /* Now for the content */ + rv = sv_PrintPKCS7ContentInfo(out, &(src->contentInfo), + "pkcs7.contentInformation="); + if (rv != 0) return rv; + + /* Parse and list certificates (if any) */ + if (src->rawCerts != NULL) { + iv = 0; + while (src->rawCerts[iv] != NULL) + iv++; + fprintf(out, "pkcs7.certificateListLength=%d\n", iv); + + iv = 0; + while ((aCert = src->rawCerts[iv]) != NULL) { + sprintf(om, "certificate[%d].", iv++); + rv = sv_PrintSignedData(out, aCert, om, sv_PrintCertificate); + if (rv) return rv; + } + } + + /* Parse and list CRL's (if any) */ + if (src->crls != NULL) { + iv = 0; + while (src->crls[iv] != NULL) iv++; + fprintf(out, "pkcs7.signedRevocationLists=%d\n", iv); + iv = 0; + while ((aCrl = src->crls[iv]) != NULL) { + sprintf(om, "signedRevocationList[%d].", iv); + fprintf(out, om); + sv_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, + "signatureAlgorithm="); + DER_ConvertBitString(&aCrl->signatureWrap.signature); + fprintf(out, om); + sv_PrintAsHex(out, &aCrl->signatureWrap.signature, "signature="); + sprintf(om, "certificateRevocationList[%d].", iv); + sv_PrintCRLInfo(out, &aCrl->crl, om); + iv++; + } + } + + /* Parse and list signatures (if any) */ + if (src->signerInfos != NULL) { + iv = 0; + while (src->signerInfos[iv] != NULL) + iv++; + fprintf(out, "pkcs7.signerInformationListLength=%d\n", iv); + iv = 0; + while ((sigInfo = src->signerInfos[iv]) != NULL) { + sprintf(om, "signerInformation[%d].", iv++); + sv_PrintSignerInfo(out, sigInfo, om); + } + } + + return 0; +} + +#if 0 +/* +** secu_PrintPKCS7Enveloped +** Pretty print a PKCS7 enveloped data type (up to version 1). +*/ +void +secu_PrintPKCS7Enveloped(FILE *out, SEC_PKCS7EnvelopedData *src, + char *m, int level) +{ + SEC_PKCS7RecipientInfo *recInfo; /* pointer for signer information */ + int iv; + char om[100]; + + secu_Indent(out, level); fprintf(out, "%s:\n", m); + sv_PrintInteger(out, &(src->version), "Version", level + 1); + + /* Parse and list recipients (this is not optional) */ + if (src->recipientInfos != NULL) { + secu_Indent(out, level + 1); + fprintf(out, "Recipient Information List:\n"); + iv = 0; + while ((recInfo = src->recipientInfos[iv++]) != NULL) { + sprintf(om, "Recipient Information (%x)", iv); + secu_PrintRecipientInfo(out, recInfo, om, level + 2); + } + } + + secu_PrintPKCS7EncContent(out, &src->encContentInfo, + "Encrypted Content Information", level + 1); +} + +/* +** secu_PrintPKCS7SignedEnveloped +** Pretty print a PKCS7 singed and enveloped data type (up to version 1). +*/ +int +secu_PrintPKCS7SignedAndEnveloped(FILE *out, + SEC_PKCS7SignedAndEnvelopedData *src, + char *m, int level) +{ + SECAlgorithmID *digAlg; /* pointer for digest algorithms */ + SECItem *aCert; /* pointer for certificate */ + CERTSignedCrl *aCrl; /* pointer for certificate revocation list */ + SEC_PKCS7SignerInfo *sigInfo; /* pointer for signer information */ + SEC_PKCS7RecipientInfo *recInfo; /* pointer for recipient information */ + int rv, iv; + char om[100]; + + secu_Indent(out, level); fprintf(out, "%s:\n", m); + sv_PrintInteger(out, &(src->version), "Version", level + 1); + + /* Parse and list recipients (this is not optional) */ + if (src->recipientInfos != NULL) { + secu_Indent(out, level + 1); + fprintf(out, "Recipient Information List:\n"); + iv = 0; + while ((recInfo = src->recipientInfos[iv++]) != NULL) { + sprintf(om, "Recipient Information (%x)", iv); + secu_PrintRecipientInfo(out, recInfo, om, level + 2); + } + } + + /* Parse and list digest algorithms (if any) */ + if (src->digestAlgorithms != NULL) { + secu_Indent(out, level + 1); fprintf(out, "Digest Algorithm List:\n"); + iv = 0; + while ((digAlg = src->digestAlgorithms[iv++]) != NULL) { + sprintf(om, "Digest Algorithm (%x)", iv); + sv_PrintAlgorithmID(out, digAlg, om); + } + } + + secu_PrintPKCS7EncContent(out, &src->encContentInfo, + "Encrypted Content Information", level + 1); + + /* Parse and list certificates (if any) */ + if (src->rawCerts != NULL) { + secu_Indent(out, level + 1); fprintf(out, "Certificate List:\n"); + iv = 0; + while ((aCert = src->rawCerts[iv++]) != NULL) { + sprintf(om, "Certificate (%x)", iv); + rv = SECU_PrintSignedData(out, aCert, om, level + 2, + SECU_PrintCertificate); + if (rv) + return rv; + } + } + + /* Parse and list CRL's (if any) */ + if (src->crls != NULL) { + secu_Indent(out, level + 1); + fprintf(out, "Signed Revocation Lists:\n"); + iv = 0; + while ((aCrl = src->crls[iv++]) != NULL) { + sprintf(om, "Signed Revocation List (%x)", iv); + secu_Indent(out, level + 2); fprintf(out, "%s:\n", om); + sv_PrintAlgorithmID(out, &aCrl->signatureWrap.signatureAlgorithm, + "Signature Algorithm"); + DER_ConvertBitString(&aCrl->signatureWrap.signature); + sv_PrintAsHex(out, &aCrl->signatureWrap.signature, "Signature", + level+3); + SECU_PrintCRLInfo(out, &aCrl->crl, "Certificate Revocation List", + level + 3); + } + } + + /* Parse and list signatures (if any) */ + if (src->signerInfos != NULL) { + secu_Indent(out, level + 1); + fprintf(out, "Signer Information List:\n"); + iv = 0; + while ((sigInfo = src->signerInfos[iv++]) != NULL) { + sprintf(om, "Signer Information (%x)", iv); + secu_PrintSignerInfo(out, sigInfo, om, level + 2); + } + } + + return 0; +} + +PR_IMPLEMENT(int) +SECU_PrintCrl (FILE *out, SECItem *der, char *m, int level) +{ + PRArenaPool *arena = NULL; + CERTCrl *c = NULL; + int rv; + + do { + /* Decode CRL */ + c = (CERTCrl*) PORT_ZAlloc(sizeof(CERTCrl)); + if (!c) { + rv = PORT_GetError(); + break; + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (!arena) { + rv = SEC_ERROR_NO_MEMORY; + break; + } + + rv = SEC_ASN1DecodeItem(arena, c, CERT_CrlTemplate, der); + if (rv != SECSuccess) + break; + SECU_PrintCRLInfo (out, c, m, level); + } while (0); + PORT_FreeArena (arena, PR_FALSE); + PORT_Free (c); + return (rv); +} + +/* +** secu_PrintPKCS7Encrypted +** Pretty print a PKCS7 encrypted data type (up to version 1). +*/ +void +secu_PrintPKCS7Encrypted(FILE *out, SEC_PKCS7EncryptedData *src, + char *m, int level) +{ + secu_Indent(out, level); fprintf(out, "%s:\n", m); + sv_PrintInteger(out, &(src->version), "Version", level + 1); + + secu_PrintPKCS7EncContent(out, &src->encContentInfo, + "Encrypted Content Information", level + 1); +} + +/* +** secu_PrintPKCS7Digested +** Pretty print a PKCS7 digested data type (up to version 1). +*/ +void +sv_PrintPKCS7Digested(FILE *out, SEC_PKCS7DigestedData *src) +{ + secu_Indent(out, level); fprintf(out, "%s:\n", m); + sv_PrintInteger(out, &(src->version), "Version", level + 1); + + sv_PrintAlgorithmID(out, &src->digestAlg, "Digest Algorithm"); + sv_PrintPKCS7ContentInfo(out, &src->contentInfo, "Content Information", + level + 1); + sv_PrintAsHex(out, &src->digest, "Digest", level + 1); +} + +#endif + +/* +** secu_PrintPKCS7ContentInfo +** Takes a SEC_PKCS7ContentInfo type and sends the contents to the +** appropriate function +*/ +int +sv_PrintPKCS7ContentInfo(FILE *out, SEC_PKCS7ContentInfo *src, char *m) +{ + const char *desc; + SECOidTag kind; + int rv; + + if (src->contentTypeTag == NULL) + src->contentTypeTag = SECOID_FindOID(&(src->contentType)); + + if (src->contentTypeTag == NULL) { + desc = "Unknown"; + kind = SEC_OID_PKCS7_DATA; + } else { + desc = src->contentTypeTag->desc; + kind = src->contentTypeTag->offset; + } + + fprintf(out, "%s%s\n", m, desc); + + if (src->content.data == NULL) { + fprintf(out, "pkcs7.data=<no content>\n"); + return 0; + } + + rv = 0; + switch (kind) { + case SEC_OID_PKCS7_SIGNED_DATA: /* Signed Data */ + rv = sv_PrintPKCS7Signed(out, src->content.signedData); + break; + + case SEC_OID_PKCS7_ENVELOPED_DATA: /* Enveloped Data */ + fprintf(out, "pkcs7EnvelopedData=<unsupported>\n"); + /*sv_PrintPKCS7Enveloped(out, src->content.envelopedData);*/ + break; + + case SEC_OID_PKCS7_SIGNED_ENVELOPED_DATA: /* Signed and Enveloped */ + fprintf(out, "pkcs7SignedEnvelopedData=<unsupported>\n"); + /*rv = sv_PrintPKCS7SignedAndEnveloped(out, + src->content.signedAndEnvelopedData);*/ + break; + + case SEC_OID_PKCS7_DIGESTED_DATA: /* Digested Data */ + fprintf(out, "pkcs7DigestedData=<unsupported>\n"); + /*sv_PrintPKCS7Digested(out, src->content.digestedData);*/ + break; + + case SEC_OID_PKCS7_ENCRYPTED_DATA: /* Encrypted Data */ + fprintf(out, "pkcs7EncryptedData=<unsupported>\n"); + /*sv_PrintPKCS7Encrypted(out, src->content.encryptedData);*/ + break; + + default: + fprintf(out, "pkcs7UnknownData=<unsupported>\n"); + /*sv_PrintAsHex(out, src->content.data);*/ + break; + } + + return rv; +} + + +int +SV_PrintPKCS7ContentInfo(FILE *out, SECItem *der) +{ + SEC_PKCS7ContentInfo *cinfo; + int rv = -1; + + cinfo = SEC_PKCS7DecodeItem(der, NULL, NULL, NULL, NULL, NULL, NULL, NULL); + + if (cinfo != NULL) { + rv = sv_PrintPKCS7ContentInfo(out, cinfo, "pkcs7.contentInfo="); + SEC_PKCS7DestroyContentInfo(cinfo); + } + + return rv; +} +/* +** End of PKCS7 functions +*/ diff --git a/security/nss/cmd/signver/signver.c b/security/nss/cmd/signver/signver.c new file mode 100644 index 000000000..ca56bc862 --- /dev/null +++ b/security/nss/cmd/signver/signver.c @@ -0,0 +1,455 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "secutil.h" +#include "secmod.h" +#include "cert.h" +#include "secoid.h" +#include "nss.h" + +/* NSPR 2.0 header files */ +#include "prinit.h" +#include "prprf.h" +#include "prsystem.h" +#include "prmem.h" +/* Portable layer header files */ +#include "plstr.h" +#include "sechash.h" /* for HASH_GetHashObject() */ + +static int debugInfo = 0; + +static char *usageInfo[] = { + "Options:", + " -a signature file is ASCII", + " -d certdir directory containing cert database", + " -i dataFileName input file name containing data,", + " leave filename blank to use stdin", + " -s signatureFileName input file name containing signature,", + " leave filename blank to use stdin", + " -o outputFileName output file name, default stdout", + " -A display all information from pkcs #7", + " -C display all information from all certs", + " -C -n display number of certificates", + " -C -n certNum display all information from the certNum", + " certificate in pkcs #7 signed object", + " -C -n certNum f1 ... fN display information about specified", + " fields from the certNum certificate in", + " the pkcs #7 signed object", + " -S display signer information list", + " -S -n display number of signer information blocks", + " -S -n signerNum display all information from the signerNum", + " signer information block in pkcs #7", + " -S -n signerNum f1 ... fN display information about specified", + " fields from the signerNum signer", + " information block in pkcs #7 object", + " -V verify the signed object and display result", + " -V -v verify the signed object and display", + " result and reason for failure", + "Version 2.0" +}; +static int nUsageInfo = sizeof(usageInfo)/sizeof(char *); + +extern int SV_PrintPKCS7ContentInfo(FILE *, SECItem *); + +static void Usage(char *progName, FILE *outFile) +{ + int i; + fprintf(outFile, "Usage: %s options\n", progName); + for (i = 0; i < nUsageInfo; i++) + fprintf(outFile, "%s\n", usageInfo[i]); + exit(-1); +} + +static HASH_HashType +AlgorithmToHashType(SECAlgorithmID *digestAlgorithms) +{ + SECOidTag tag; + + tag = SECOID_GetAlgorithmTag(digestAlgorithms); + + switch (tag) { + case SEC_OID_MD2: + if (debugInfo) PR_fprintf(PR_STDERR, "Hash algorithm: HASH_AlgMD2 SEC_OID_MD2\n"); + return HASH_AlgMD2; + case SEC_OID_MD5: + if (debugInfo) PR_fprintf(PR_STDERR, "Hash algorithm: HASH_AlgMD5 SEC_OID_MD5\n"); + return HASH_AlgMD5; + case SEC_OID_SHA1: + if (debugInfo) PR_fprintf(PR_STDERR, "Hash algorithm: HASH_AlgSHA1 SEC_OID_SHA1\n"); + return HASH_AlgSHA1; + default: + if (debugInfo) PR_fprintf(PR_STDERR, "should never get here\n"); + return HASH_AlgNULL; + } +} + + +static int +DigestData (unsigned char *digest, unsigned char *data, + unsigned int *len, unsigned int maxLen, + HASH_HashType hashType) +{ + const SECHashObject *hashObj; + void *hashcx; + + hashObj = HASH_GetHashObject(hashType); + hashcx = (* hashObj->create)(); + if (hashcx == NULL) + return -1; + + (* hashObj->begin)(hashcx); + (* hashObj->update)(hashcx, data, PORT_Strlen((char *)data)); + (* hashObj->end)(hashcx, digest, len, maxLen); + (* hashObj->destroy)(hashcx, PR_TRUE); + + return 0; +} + +enum { + cmd_DisplayAllPCKS7Info = 0, + cmd_DisplayCertInfo, + cmd_DisplaySignerInfo, + cmd_VerifySignedObj +}; + +enum { + opt_ASCII, + opt_CertDir, + opt_InputDataFile, + opt_ItemNumber, + opt_OutputFile, + opt_InputSigFile, + opt_TypeTag, + opt_PrintWhyFailure +}; + +static secuCommandFlag signver_commands[] = +{ + { /* cmd_DisplayAllPCKS7Info*/ 'A', PR_FALSE, 0, PR_FALSE }, + { /* cmd_DisplayCertInfo */ 'C', PR_FALSE, 0, PR_FALSE }, + { /* cmd_DisplaySignerInfo */ 'S', PR_FALSE, 0, PR_FALSE }, + { /* cmd_VerifySignedObj */ 'V', PR_FALSE, 0, PR_FALSE } +}; + +static secuCommandFlag signver_options[] = +{ + { /* opt_ASCII */ 'a', PR_FALSE, 0, PR_FALSE }, + { /* opt_CertDir */ 'd', PR_TRUE, 0, PR_FALSE }, + { /* opt_InputDataFile */ 'i', PR_TRUE, 0, PR_FALSE }, + { /* opt_ItemNumber */ 'n', PR_FALSE, 0, PR_FALSE }, + { /* opt_OutputFile */ 'o', PR_TRUE, 0, PR_FALSE }, + { /* opt_InputSigFile */ 's', PR_TRUE, 0, PR_FALSE }, + { /* opt_TypeTag */ 't', PR_TRUE, 0, PR_FALSE }, + { /* opt_PrintWhyFailure */ 'v', PR_FALSE, 0, PR_FALSE } +}; + +int main(int argc, char **argv) +{ + PRExplodedTime explodedCurrent; + SECItem der, data; + char *progName; + int rv; + PRFileDesc *dataFile = 0; + PRFileDesc *signFile = 0; + FILE *outFile = stdout; + char *typeTag = 0; + PRBool displayAllCerts = PR_FALSE; + PRBool displayAllSigners = PR_FALSE; + PRFileInfo info; + PRInt32 nb; + SECStatus secstatus; + + secuCommand signver; + signver.numCommands = sizeof(signver_commands) /sizeof(secuCommandFlag); + signver.numOptions = sizeof(signver_options) / sizeof(secuCommandFlag); + signver.commands = signver_commands; + signver.options = signver_options; + +#ifdef XP_PC + progName = strrchr(argv[0], '\\'); +#else + progName = strrchr(argv[0], '/'); +#endif + progName = progName ? progName+1 : argv[0]; + + /*_asm int 3*/ + + PR_ExplodeTime(PR_Now(), PR_LocalTimeParameters, &explodedCurrent); +#if 0 + if (explodedCurrent.tm_year >= 1998 + && explodedCurrent.tm_month >= 5 /* months past tm_year (0-11, Jan = 0) */ + && explodedCurrent.tm_mday >= 1) { + PR_fprintf(PR_STDERR, "%s: expired\n", progName); + return -1; + } +#endif + + SECU_ParseCommandLine(argc, argv, progName, &signver); + + /* Set the certdb directory (default is ~/.{browser}) */ + SECU_ConfigDirectory(signver.options[opt_CertDir].arg); + + /* Set the certificate type. */ + typeTag = SECU_GetOptionArg(&signver, opt_TypeTag); + + /* -i and -s without filenames */ + if (signver.options[opt_InputDataFile].activated && + signver.options[opt_InputSigFile].activated && + !signver.options[opt_InputDataFile].arg && + !signver.options[opt_InputSigFile].arg) + PR_fprintf(PR_STDERR, + "%s: Only data or signature file can use stdin (not both).\n", + progName); + + /* Open the input data file (no arg == use stdin). */ + if (signver.options[opt_InputDataFile].activated) { + if (signver.options[opt_InputDataFile].arg) + dataFile = PR_Open(signver.options[opt_InputDataFile].arg, + PR_RDONLY, 0); + else + dataFile = PR_STDIN; + if (!dataFile) { + PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading.\n", + progName, signver.options[opt_InputDataFile].arg); + return -1; + } + } + + /* Open the input signature file (no arg == use stdin). */ + if (signver.options[opt_InputSigFile].activated) { + if (signver.options[opt_InputSigFile].arg) + signFile = PR_Open(signver.options[opt_InputSigFile].arg, + PR_RDONLY, 0); + else + signFile = PR_STDIN; + if (!signFile) { + PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for reading.\n", + progName, signver.options[opt_InputSigFile].arg); + return -1; + } + } + +#if 0 + if (!typeTag) ascii = 1; +#endif + + /* Open|Create the output file. */ + if (signver.options[opt_OutputFile].activated) { + outFile = fopen(signver.options[opt_OutputFile].arg, "w"); + /* + outFile = PR_Open(signver.options[opt_OutputFile].arg, + PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE, 00660); + */ + if (!outFile) { + PR_fprintf(PR_STDERR, "%s: unable to open \"%s\" for writing.\n", + progName, signver.options[opt_OutputFile].arg); + return -1; + } + } + + if (signver.commands[cmd_DisplayCertInfo].activated && + !signver.options[opt_ItemNumber].arg) + displayAllCerts = PR_TRUE; + + if (signver.commands[cmd_DisplaySignerInfo].activated && + !signver.options[opt_ItemNumber].arg) + displayAllSigners = PR_TRUE; + +#if 0 + case 'W': + debugInfo = 1; + break; +#endif + + if (!signFile && !dataFile && !typeTag) + Usage(progName, outFile); + + if (!signFile && !dataFile && + signver.commands[cmd_VerifySignedObj].activated) { + PR_fprintf(PR_STDERR, + "%s: unable to read all data from standard input\n", + progName); + return -1; + } + + PR_SetError(0, 0); /* PR_Init("pp", 1, 1, 0);*/ + secstatus = NSS_Init(SECU_ConfigDirectory(NULL)); + if (secstatus != SECSuccess) { + SECU_PrintPRandOSError(progName); + return -1; + } + + rv = SECU_ReadDERFromFile(&der, signFile, + signver.options[opt_ASCII].activated); + + /* Data is untyped, using the specified type */ + data.data = der.data; + data.len = der.len; + + + /* Signature Verification */ + if (!signver.options[opt_TypeTag].activated) { + if (signver.commands[cmd_VerifySignedObj].activated) { + SEC_PKCS7ContentInfo *cinfo; + + cinfo = SEC_PKCS7DecodeItem(&data, NULL, NULL, NULL, NULL, + NULL, NULL, NULL); + if (cinfo != NULL) { +#if 0 + if (debugInfo) { + PR_fprintf(PR_STDERR, "Content %s encrypted.\n", + SEC_PKCS7ContentIsEncrypted(cinfo) ? "was" : "was not"); + + PR_fprintf(PR_STDERR, "Content %s signed.\n", + SEC_PKCS7ContentIsSigned(cinfo) ? "was" : "was not"); + } +#endif + + if (SEC_PKCS7ContentIsSigned(cinfo)) { + SEC_PKCS7SignedData *signedData; + HASH_HashType digestType; + SECItem digest, data; + unsigned char *dataToVerify, digestBuffer[32]; + + signedData = cinfo->content.signedData; + + /* assume that there is only one digest algorithm for now */ + digestType = + AlgorithmToHashType(signedData->digestAlgorithms[0]); + if (digestType == HASH_AlgNULL) { + PR_fprintf(PR_STDERR, "Invalid hash algorithmID\n"); + return (-1); + } + rv = SECU_FileToItem(&data, dataFile); + dataToVerify = data.data; + if (dataToVerify) { + /*certUsageObjectSigner;*/ + SECCertUsage usage = certUsageEmailSigner; + + +#if 0 + if (debugInfo) + PR_fprintf(PR_STDERR, "dataToVerify=%s\n", + dataToVerify); +#endif + digest.data = digestBuffer; + if (DigestData (digest.data, dataToVerify, + &digest.len, 32, digestType)) { + PR_fprintf(PR_STDERR, "Fail to compute message digest for verification. Reason: %s\n", + SECU_ErrorString((int16)PORT_GetError())); + return (-1); + } +#if 0 + if (debugInfo) { + PR_fprintf(PR_STDERR, "Data Digest=:"); + for (i = 0; i < digest.len; i++) + PR_fprintf(PR_STDERR, "%02x:", digest.data[i]); + PR_fprintf(PR_STDERR, "\n"); + } +#endif + + + if (signver.commands[cmd_VerifySignedObj].activated) + fprintf(outFile, "signatureValid="); + PORT_SetError(0); + if (SEC_PKCS7VerifyDetachedSignature (cinfo, usage, + &digest, digestType, PR_FALSE)) { + if (signver.commands[cmd_VerifySignedObj].activated) + fprintf(outFile, "yes"); + } else { + if (signver.commands[cmd_VerifySignedObj].activated){ + fprintf(outFile, "no"); + if (signver.options[opt_PrintWhyFailure].activated) + fprintf(outFile, ":%s", SECU_ErrorString((int16)PORT_GetError())); + } + } + if (signver.commands[cmd_VerifySignedObj].activated) + fprintf(outFile, "\n"); + + SECITEM_FreeItem(&data, PR_FALSE); + } else { + PR_fprintf(PR_STDERR, "Cannot read data\n"); + return (-1); + } + } + + SEC_PKCS7DestroyContentInfo(cinfo); + } else + PR_fprintf(PR_STDERR, "Unable to decode PKCS7 data\n"); + } + + if (signver.commands[cmd_DisplayAllPCKS7Info].activated) + SV_PrintPKCS7ContentInfo(outFile, &data); + + if (displayAllCerts) + PR_fprintf(PR_STDERR, "-C option is not implemented in this version\n"); + + if (displayAllSigners) + PR_fprintf(PR_STDERR, "-S option is not implemented in this version\n"); + + /* Pretty print it */ + } else if (PL_strcmp(typeTag, SEC_CT_CERTIFICATE) == 0) { + rv = SECU_PrintSignedData(outFile, &data, "Certificate", 0, + SECU_PrintCertificate); + } else if (PL_strcmp(typeTag, SEC_CT_CERTIFICATE_REQUEST) == 0) { + rv = SECU_PrintSignedData(outFile, &data, "Certificate Request", 0, + SECU_PrintCertificateRequest); + } else if (PL_strcmp (typeTag, SEC_CT_CRL) == 0) { + rv = SECU_PrintSignedData (outFile, &data, "CRL", 0, SECU_PrintCrl); +#ifdef HAVE_EPK_TEMPLATE + } else if (PL_strcmp(typeTag, SEC_CT_PRIVATE_KEY) == 0) { + rv = SECU_PrintPrivateKey(outFile, &data, "Private Key", 0); +#endif + } else if (PL_strcmp(typeTag, SEC_CT_PUBLIC_KEY) == 0) { + rv = SECU_PrintPublicKey(outFile, &data, "Public Key", 0); + } else if (PL_strcmp(typeTag, SEC_CT_PKCS7) == 0) { + rv = SECU_PrintPKCS7ContentInfo(outFile, &data, + "PKCS #7 Content Info", 0); + } else { + PR_fprintf(PR_STDERR, "%s: don't know how to print out '%s' files\n", + progName, typeTag); + return -1; + } + + if (rv) { + PR_fprintf(PR_STDERR, "%s: problem converting data (%s)\n", + progName, SECU_ErrorString((int16)PORT_GetError())); + return -1; + } + + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + + return 0; +} diff --git a/security/nss/cmd/smimetools/Makefile b/security/nss/cmd/smimetools/Makefile new file mode 100644 index 000000000..9e3263d43 --- /dev/null +++ b/security/nss/cmd/smimetools/Makefile @@ -0,0 +1,73 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +include rules.mk + +include ../platrules.mk diff --git a/security/nss/cmd/smimetools/cmsutil.c b/security/nss/cmd/smimetools/cmsutil.c new file mode 100644 index 000000000..3af802431 --- /dev/null +++ b/security/nss/cmd/smimetools/cmsutil.c @@ -0,0 +1,1450 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* + * cmsutil -- A command to work with CMS data + * + * $Id$ + */ + +#include "nspr.h" +#include "secutil.h" +#include "plgetopt.h" +#include "secpkcs7.h" +#include "cert.h" +#include "certdb.h" +#include "secoid.h" +#include "cms.h" +#include "nss.h" +#include "smime.h" +#include "pk11func.h" + +#if defined(XP_UNIX) +#include <unistd.h> +#endif + +#if defined(_WIN32) +#include "fcntl.h" +#include "io.h" +#endif + +#include <stdio.h> +#include <string.h> + +extern void SEC_Init(void); /* XXX */ +char *progName = NULL; +static int cms_verbose = 0; + +/* XXX stolen from cmsarray.c + * nss_CMSArray_Count - count number of elements in array + */ +int +nss_CMSArray_Count(void **array) +{ + int n = 0; + if (array == NULL) + return 0; + while (*array++ != NULL) + n++; + return n; +} + +static SECStatus +DigestFile(PLArenaPool *poolp, SECItem ***digests, SECItem *input, + SECAlgorithmID **algids) +{ + NSSCMSDigestContext *digcx; + + digcx = NSS_CMSDigestContext_StartMultiple(algids); + if (digcx == NULL) + return SECFailure; + + NSS_CMSDigestContext_Update(digcx, input->data, input->len); + + return NSS_CMSDigestContext_FinishMultiple(digcx, poolp, digests); +} + + +static void +Usage(char *progName) +{ + fprintf(stderr, +"Usage: %s [-D|-S|-E] [<options>] [-d dbdir] [-u certusage]\n", + progName); + fprintf(stderr, +" -D decode a CMS message\n" +" -c content use this detached content\n" +" -n suppress output of content\n" +" -h num generate email headers with info about CMS message\n" +" -S create a CMS signed message\n" +" -G include a signing time attribute\n" +" -H hash use hash (default:SHA1)\n" +" -N nick use certificate named \"nick\" for signing\n" +" -P include a SMIMECapabilities attribute\n" +" -T do not include content in CMS message\n" +" -Y nick include a EncryptionKeyPreference attribute with cert\n" +" (use \"NONE\" to omit)\n" +" -E create a CMS enveloped message (NYI)\n" +" -r id,... create envelope for these recipients,\n" +" where id can be a certificate nickname or email address\n" +" -d dbdir key/cert database directory (default: ~/.netscape)\n" +" -i infile use infile as source of data (default: stdin)\n" +" -o outfile use outfile as destination of data (default: stdout)\n" +" -p password use password as key db password (default: prompt)\n" +" -u certusage set type of certificate usage (default: certUsageEmailSigner)\n" +" -v print debugging information\n" +"\nCert usage codes:\n"); + fprintf(stderr, "%-25s 0 - certUsageSSLClient\n", " "); + fprintf(stderr, "%-25s 1 - certUsageSSLServer\n", " "); + fprintf(stderr, "%-25s 2 - certUsageSSLServerWithStepUp\n", " "); + fprintf(stderr, "%-25s 3 - certUsageSSLCA\n", " "); + fprintf(stderr, "%-25s 4 - certUsageEmailSigner\n", " "); + fprintf(stderr, "%-25s 5 - certUsageEmailRecipient\n", " "); + fprintf(stderr, "%-25s 6 - certUsageObjectSigner\n", " "); + fprintf(stderr, "%-25s 7 - certUsageUserCertImport\n", " "); + fprintf(stderr, "%-25s 8 - certUsageVerifyCA\n", " "); + fprintf(stderr, "%-25s 9 - certUsageProtectedObjectSigner\n", " "); + fprintf(stderr, "%-25s 10 - certUsageStatusResponder\n", " "); + fprintf(stderr, "%-25s 11 - certUsageAnyCA\n", " "); + + exit(-1); +} + +struct optionsStr { + char *password; + SECCertUsage certUsage; + CERTCertDBHandle *certHandle; +}; + +struct decodeOptionsStr { + struct optionsStr *options; + PRFileDesc *contentFile; + int headerLevel; + PRBool suppressContent; + NSSCMSGetDecryptKeyCallback dkcb; + PK11SymKey *bulkkey; +}; + +struct signOptionsStr { + struct optionsStr *options; + char *nickname; + char *encryptionKeyPreferenceNick; + PRBool signingTime; + PRBool smimeProfile; + PRBool detached; + SECOidTag hashAlgTag; +}; + +struct envelopeOptionsStr { + struct optionsStr *options; + char **recipients; +}; + +struct certsonlyOptionsStr { + struct optionsStr *options; + char **recipients; +}; + +struct encryptOptionsStr { + struct optionsStr *options; + char **recipients; + NSSCMSMessage *envmsg; + SECItem *input; + FILE *outfile; + PRFileDesc *envFile; + PK11SymKey *bulkkey; + SECOidTag bulkalgtag; + int keysize; +}; + +static NSSCMSMessage * +decode(FILE *out, SECItem *output, SECItem *input, + const struct decodeOptionsStr *decodeOptions) +{ + NSSCMSDecoderContext *dcx; + NSSCMSMessage *cmsg; + NSSCMSContentInfo *cinfo; + NSSCMSSignedData *sigd = NULL; + NSSCMSEnvelopedData *envd; + NSSCMSEncryptedData *encd; + SECAlgorithmID **digestalgs; + int nlevels, i, nsigners, j; + char *signercn; + NSSCMSSignerInfo *si; + SECOidTag typetag; + SECItem **digests; + PLArenaPool *poolp; + PK11PasswordFunc pwcb; + void *pwcb_arg; + SECItem *item, sitem = { 0, 0, 0 }; + secuPWData pwdata = { PW_NONE, 0 }; + + if (decodeOptions->options->password) + { + pwdata.source = PW_PLAINTEXT; + pwdata.data = decodeOptions->options->password; + } + pwcb = SECU_GetModulePassword; + pwcb_arg = (void *)&pwdata; + + if (decodeOptions->contentFile) { + /* detached content: grab content file */ + SECU_FileToItem(&sitem, decodeOptions->contentFile); + } + + dcx = NSS_CMSDecoder_Start(NULL, + NULL, NULL, /* content callback */ + pwcb, pwcb_arg, /* password callback */ + decodeOptions->dkcb, /* decrypt key callback */ + decodeOptions->bulkkey); + (void)NSS_CMSDecoder_Update(dcx, (char *)input->data, input->len); + cmsg = NSS_CMSDecoder_Finish(dcx); + if (cmsg == NULL) { + fprintf(stderr, "%s: failed to decode message.\n", progName); + return NULL; + } + + if (decodeOptions->headerLevel >= 0) { + /*fprintf(out, "SMIME: ", decodeOptions->headerLevel, i);*/ + fprintf(out, "SMIME: "); + } + + nlevels = NSS_CMSMessage_ContentLevelCount(cmsg); + for (i = 0; i < nlevels; i++) { + cinfo = NSS_CMSMessage_ContentLevel(cmsg, i); + typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo); + + if (decodeOptions->headerLevel >= 0) + fprintf(out, "\tlevel=%d.%d; ", decodeOptions->headerLevel, nlevels - i); + + switch (typetag) { + case SEC_OID_PKCS7_SIGNED_DATA: + if (decodeOptions->headerLevel >= 0) + fprintf(out, "type=signedData; "); + sigd = (NSSCMSSignedData *)NSS_CMSContentInfo_GetContent(cinfo); + if (sigd == NULL) { + SECU_PrintError(progName, + "problem finding signedData component"); + goto loser; + } + + /* if we have a content file, but no digests for this signedData */ + if (decodeOptions->contentFile != NULL && !NSS_CMSSignedData_HasDigests(sigd)) { + if ((poolp = PORT_NewArena(1024)) == NULL) { + fprintf(stderr, "cmsutil: Out of memory.\n"); + goto loser; + } + digestalgs = NSS_CMSSignedData_GetDigestAlgs(sigd); + if (DigestFile (poolp, &digests, &sitem, digestalgs) + != SECSuccess) { + SECU_PrintError(progName, + "problem computing message digest"); + goto loser; + } + if (NSS_CMSSignedData_SetDigests(sigd, digestalgs, digests) != SECSuccess) { + + SECU_PrintError(progName, + "problem setting message digests"); + goto loser; + } + PORT_FreeArena(poolp, PR_FALSE); + } + + /* import the certificates */ + if (NSS_CMSSignedData_ImportCerts(sigd, + decodeOptions->options->certHandle, + decodeOptions->options->certUsage, + PR_FALSE) + != SECSuccess) { + SECU_PrintError(progName, "cert import failed"); + goto loser; + } + + /* find out about signers */ + nsigners = NSS_CMSSignedData_SignerInfoCount(sigd); + if (decodeOptions->headerLevel >= 0) + fprintf(out, "nsigners=%d; ", nsigners); + if (nsigners == 0) { + /* must be a cert transport message */ + SECStatus rv; + /* XXX workaround for bug #54014 */ + NSS_CMSSignedData_ImportCerts(sigd, + decodeOptions->options->certHandle, + decodeOptions->options->certUsage, + PR_TRUE); + rv = NSS_CMSSignedData_VerifyCertsOnly(sigd, + decodeOptions->options->certHandle, + decodeOptions->options->certUsage); + if (rv != SECSuccess) { + fprintf(stderr, "cmsutil: Verify certs-only failed!\n"); + goto loser; + } + return cmsg; + } + + /* still no digests? */ + if (!NSS_CMSSignedData_HasDigests(sigd)) { + SECU_PrintError(progName, "no message digests"); + goto loser; + } + + for (j = 0; j < nsigners; j++) { + si = NSS_CMSSignedData_GetSignerInfo(sigd, j); + signercn = NSS_CMSSignerInfo_GetSignerCommonName(si); + if (signercn == NULL) + signercn = ""; + if (decodeOptions->headerLevel >= 0) + fprintf(out, "\n\t\tsigner%d.id=\"%s\"; ", j, signercn); + (void)NSS_CMSSignedData_VerifySignerInfo(sigd, j, + decodeOptions->options->certHandle, + decodeOptions->options->certUsage); + if (decodeOptions->headerLevel >= 0) + fprintf(out, "signer%d.status=%s; ", j, + NSS_CMSUtil_VerificationStatusToString( + NSS_CMSSignerInfo_GetVerificationStatus(si))); + /* XXX what do we do if we don't print headers? */ + } + break; + case SEC_OID_PKCS7_ENVELOPED_DATA: + if (decodeOptions->headerLevel >= 0) + fprintf(out, "type=envelopedData; "); + envd = (NSSCMSEnvelopedData *)NSS_CMSContentInfo_GetContent(cinfo); + break; + case SEC_OID_PKCS7_ENCRYPTED_DATA: + if (decodeOptions->headerLevel >= 0) + fprintf(out, "type=encryptedData; "); + encd = (NSSCMSEncryptedData *)NSS_CMSContentInfo_GetContent(cinfo); + break; + case SEC_OID_PKCS7_DATA: + if (decodeOptions->headerLevel >= 0) + fprintf(out, "type=data; "); + break; + default: + break; + } + if (decodeOptions->headerLevel >= 0) + fprintf(out, "\n"); + } + + if (!decodeOptions->suppressContent) { + item = decodeOptions->contentFile ? &sitem : + NSS_CMSMessage_GetContent(cmsg); + SECITEM_CopyItem(NULL, output, item); + } + + return cmsg; +loser: + if (cmsg) + NSS_CMSMessage_Destroy(cmsg); + return NULL; +} + +/* example of a callback function to use with encoder */ +/* +static void +writeout(void *arg, const char *buf, unsigned long len) +{ + FILE *f = (FILE *)arg; + + if (f != NULL && buf != NULL) + (void)fwrite(buf, len, 1, f); +} +*/ + +static NSSCMSMessage * +signed_data(struct signOptionsStr *signOptions) +{ + NSSCMSMessage *cmsg = NULL; + NSSCMSContentInfo *cinfo; + NSSCMSSignedData *sigd; + NSSCMSSignerInfo *signerinfo; + CERTCertificate *cert= NULL, *ekpcert = NULL; + + if (cms_verbose) { + fprintf(stderr, "Input to signed_data:\n"); + if (signOptions->options->password) + fprintf(stderr, "password [%s]\n", signOptions->options->password); + else + fprintf(stderr, "password [NULL]\n"); + fprintf(stderr, "certUsage [%d]\n", signOptions->options->certUsage); + if (signOptions->options->certHandle) + fprintf(stderr, "certdb [%p]\n", signOptions->options->certHandle); + else + fprintf(stderr, "certdb [NULL]\n"); + if (signOptions->nickname) + fprintf(stderr, "nickname [%s]\n", signOptions->nickname); + else + fprintf(stderr, "nickname [NULL]\n"); + } + if (signOptions->nickname == NULL) { + fprintf(stderr, + "ERROR: please indicate the nickname of a certificate to sign with.\n"); + return NULL; + } + if ((cert = CERT_FindUserCertByUsage(signOptions->options->certHandle, + signOptions->nickname, + signOptions->options->certUsage, + PR_FALSE, + NULL)) == NULL) { + SECU_PrintError(progName, + "the corresponding cert for key \"%s\" does not exist", + signOptions->nickname); + return NULL; + } + if (cms_verbose) { + fprintf(stderr, "Found certificate for %s\n", signOptions->nickname); + } + /* + * create the message object + */ + cmsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */ + if (cmsg == NULL) { + fprintf(stderr, "ERROR: cannot create CMS message.\n"); + return NULL; + } + /* + * build chain of objects: message->signedData->data + */ + if ((sigd = NSS_CMSSignedData_Create(cmsg)) == NULL) { + fprintf(stderr, "ERROR: cannot create CMS signedData object.\n"); + goto loser; + } + cinfo = NSS_CMSMessage_GetContentInfo(cmsg); + if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd) + != SECSuccess) { + fprintf(stderr, "ERROR: cannot attach CMS signedData object.\n"); + goto loser; + } + cinfo = NSS_CMSSignedData_GetContentInfo(sigd); + /* we're always passing data in and detaching optionally */ + if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, + signOptions->detached) + != SECSuccess) { + fprintf(stderr, "ERROR: cannot attach CMS data object.\n"); + goto loser; + } + /* + * create & attach signer information + */ + signerinfo = NSS_CMSSignerInfo_Create(cmsg, cert, signOptions->hashAlgTag); + if (signerinfo == NULL) { + fprintf(stderr, "ERROR: cannot create CMS signerInfo object.\n"); + goto loser; + } + if (cms_verbose) { + fprintf(stderr, + "Created CMS message, added signed data w/ signerinfo\n"); + } + /* we want the cert chain included for this one */ + if (NSS_CMSSignerInfo_IncludeCerts(signerinfo, NSSCMSCM_CertChain, + signOptions->options->certUsage) + != SECSuccess) { + fprintf(stderr, "ERROR: cannot find cert chain.\n"); + goto loser; + } + if (cms_verbose) { + fprintf(stderr, "imported certificate\n"); + } + if (signOptions->signingTime) { + if (NSS_CMSSignerInfo_AddSigningTime(signerinfo, PR_Now()) + != SECSuccess) { + fprintf(stderr, "ERROR: cannot add signingTime attribute.\n"); + goto loser; + } + } + if (signOptions->smimeProfile) { + if (NSS_CMSSignerInfo_AddSMIMECaps(signerinfo) != SECSuccess) { + fprintf(stderr, "ERROR: cannot add SMIMECaps attribute.\n"); + goto loser; + } + } + + if (!signOptions->encryptionKeyPreferenceNick) { + /* check signing cert for fitness as encryption cert */ + SECStatus FitForEncrypt = CERT_CheckCertUsage(cert, + certUsageEmailRecipient); + + if (SECSuccess == FitForEncrypt) { + /* if yes, add signing cert as EncryptionKeyPreference */ + if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, cert, + signOptions->options->certHandle) + != SECSuccess) { + fprintf(stderr, + "ERROR: cannot add default SMIMEEncKeyPrefs attribute.\n"); + goto loser; + } + if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, cert, + signOptions->options->certHandle) + != SECSuccess) { + fprintf(stderr, + "ERROR: cannot add default MS SMIMEEncKeyPrefs attribute.\n"); + goto loser; + } + } else { + /* this is a dual-key cert case, we need to look for the encryption + certificate under the same nickname as the signing cert */ + /* get the cert, add it to the message */ + if ((ekpcert = CERT_FindUserCertByUsage( + signOptions->options->certHandle, + signOptions->nickname, + certUsageEmailRecipient, + PR_FALSE, + NULL)) == NULL) { + SECU_PrintError(progName, + "the corresponding cert for key \"%s\" does not exist", + signOptions->encryptionKeyPreferenceNick); + goto loser; + } + if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, ekpcert, + signOptions->options->certHandle) + != SECSuccess) { + fprintf(stderr, + "ERROR: cannot add SMIMEEncKeyPrefs attribute.\n"); + goto loser; + } + if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, ekpcert, + signOptions->options->certHandle) + != SECSuccess) { + fprintf(stderr, + "ERROR: cannot add MS SMIMEEncKeyPrefs attribute.\n"); + goto loser; + } + if (NSS_CMSSignedData_AddCertificate(sigd, ekpcert) != SECSuccess) { + fprintf(stderr, "ERROR: cannot add encryption certificate.\n"); + goto loser; + } + } + } else if (PL_strcmp(signOptions->encryptionKeyPreferenceNick, "NONE") == 0) { + /* No action */ + } else { + /* get the cert, add it to the message */ + if ((ekpcert = CERT_FindUserCertByUsage( + signOptions->options->certHandle, + signOptions->encryptionKeyPreferenceNick, + certUsageEmailRecipient, PR_FALSE, NULL)) + == NULL) { + SECU_PrintError(progName, + "the corresponding cert for key \"%s\" does not exist", + signOptions->encryptionKeyPreferenceNick); + goto loser; + } + if (NSS_CMSSignerInfo_AddSMIMEEncKeyPrefs(signerinfo, ekpcert, + signOptions->options->certHandle) + != SECSuccess) { + fprintf(stderr, "ERROR: cannot add SMIMEEncKeyPrefs attribute.\n"); + goto loser; + } + if (NSS_CMSSignerInfo_AddMSSMIMEEncKeyPrefs(signerinfo, ekpcert, + signOptions->options->certHandle) + != SECSuccess) { + fprintf(stderr, "ERROR: cannot add MS SMIMEEncKeyPrefs attribute.\n"); + goto loser; + } + if (NSS_CMSSignedData_AddCertificate(sigd, ekpcert) != SECSuccess) { + fprintf(stderr, "ERROR: cannot add encryption certificate.\n"); + goto loser; + } + } + + if (NSS_CMSSignedData_AddSignerInfo(sigd, signerinfo) != SECSuccess) { + fprintf(stderr, "ERROR: cannot add CMS signerInfo object.\n"); + goto loser; + } + if (cms_verbose) { + fprintf(stderr, "created signed-data message\n"); + } + if (ekpcert) { + CERT_DestroyCertificate(ekpcert); + } + if (cert) { + CERT_DestroyCertificate(cert); + } + return cmsg; +loser: + if (ekpcert) { + CERT_DestroyCertificate(ekpcert); + } + if (cert) { + CERT_DestroyCertificate(cert); + } + NSS_CMSMessage_Destroy(cmsg); + return NULL; +} + +static NSSCMSMessage * +enveloped_data(struct envelopeOptionsStr *envelopeOptions) +{ + NSSCMSMessage *cmsg = NULL; + NSSCMSContentInfo *cinfo; + NSSCMSEnvelopedData *envd; + NSSCMSRecipientInfo *recipientinfo; + CERTCertificate **recipientcerts = NULL; + CERTCertDBHandle *dbhandle; + PLArenaPool *tmppoolp = NULL; + SECOidTag bulkalgtag; + int keysize, i = 0; + int cnt; + dbhandle = envelopeOptions->options->certHandle; + /* count the recipients */ + if ((cnt = nss_CMSArray_Count((void **)envelopeOptions->recipients)) == 0) { + fprintf(stderr, "ERROR: please name at least one recipient.\n"); + goto loser; + } + if ((tmppoolp = PORT_NewArena (1024)) == NULL) { + fprintf(stderr, "ERROR: out of memory.\n"); + goto loser; + } + /* XXX find the recipient's certs by email address or nickname */ + if ((recipientcerts = + (CERTCertificate **)PORT_ArenaZAlloc(tmppoolp, + (cnt+1)*sizeof(CERTCertificate*))) + == NULL) { + fprintf(stderr, "ERROR: out of memory.\n"); + goto loser; + } + for (i=0; envelopeOptions->recipients[i] != NULL; i++) { + if ((recipientcerts[i] = + CERT_FindCertByNicknameOrEmailAddr(dbhandle, + envelopeOptions->recipients[i])) + == NULL) { + SECU_PrintError(progName, "cannot find certificate for \"%s\"", + envelopeOptions->recipients[i]); + i=0; + goto loser; + } + } + recipientcerts[i] = NULL; + i=0; + /* find a nice bulk algorithm */ + if (NSS_SMIMEUtil_FindBulkAlgForRecipients(recipientcerts, &bulkalgtag, + &keysize) != SECSuccess) { + fprintf(stderr, "ERROR: cannot find common bulk algorithm.\n"); + goto loser; + } + /* + * create the message object + */ + cmsg = NSS_CMSMessage_Create(NULL); /* create a message on its own pool */ + if (cmsg == NULL) { + fprintf(stderr, "ERROR: cannot create CMS message.\n"); + goto loser; + } + /* + * build chain of objects: message->envelopedData->data + */ + if ((envd = NSS_CMSEnvelopedData_Create(cmsg, bulkalgtag, keysize)) + == NULL) { + fprintf(stderr, "ERROR: cannot create CMS envelopedData object.\n"); + goto loser; + } + cinfo = NSS_CMSMessage_GetContentInfo(cmsg); + if (NSS_CMSContentInfo_SetContent_EnvelopedData(cmsg, cinfo, envd) + != SECSuccess) { + fprintf(stderr, "ERROR: cannot attach CMS envelopedData object.\n"); + goto loser; + } + cinfo = NSS_CMSEnvelopedData_GetContentInfo(envd); + /* we're always passing data in, so the content is NULL */ + if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) + != SECSuccess) { + fprintf(stderr, "ERROR: cannot attach CMS data object.\n"); + goto loser; + } + /* + * create & attach recipient information + */ + for (i = 0; recipientcerts[i] != NULL; i++) { + if ((recipientinfo = NSS_CMSRecipientInfo_Create(cmsg, + recipientcerts[i])) + == NULL) { + fprintf(stderr, "ERROR: cannot create CMS recipientInfo object.\n"); + goto loser; + } + if (NSS_CMSEnvelopedData_AddRecipient(envd, recipientinfo) + != SECSuccess) { + fprintf(stderr, "ERROR: cannot add CMS recipientInfo object.\n"); + goto loser; + } + CERT_DestroyCertificate(recipientcerts[i]); + } + if (tmppoolp) + PORT_FreeArena(tmppoolp, PR_FALSE); + return cmsg; +loser: + if (recipientcerts) { + for (; recipientcerts[i] != NULL; i++) { + CERT_DestroyCertificate(recipientcerts[i]); + } + } + if (cmsg) + NSS_CMSMessage_Destroy(cmsg); + if (tmppoolp) + PORT_FreeArena(tmppoolp, PR_FALSE); + return NULL; +} + +PK11SymKey *dkcb(void *arg, SECAlgorithmID *algid) +{ + return (PK11SymKey*)arg; +} + +static SECStatus +get_enc_params(struct encryptOptionsStr *encryptOptions) +{ + struct envelopeOptionsStr envelopeOptions; + SECStatus rv = SECFailure; + NSSCMSMessage *env_cmsg; + NSSCMSContentInfo *cinfo; + int i, nlevels; + /* + * construct an enveloped data message to obtain bulk keys + */ + if (encryptOptions->envmsg) { + env_cmsg = encryptOptions->envmsg; /* get it from an old message */ + } else { + SECItem dummyOut = { 0, 0, 0 }; + SECItem dummyIn = { 0, 0, 0 }; + char str[] = "Hello!"; + PLArenaPool *tmparena = PORT_NewArena(1024); + dummyIn.data = (unsigned char *)str; + dummyIn.len = strlen(str); + envelopeOptions.options = encryptOptions->options; + envelopeOptions.recipients = encryptOptions->recipients; + env_cmsg = enveloped_data(&envelopeOptions); + NSS_CMSDEREncode(env_cmsg, &dummyIn, &dummyOut, tmparena); + PR_Write(encryptOptions->envFile, dummyOut.data, dummyOut.len); + PORT_FreeArena(tmparena, PR_FALSE); + } + /* + * get the content info for the enveloped data + */ + nlevels = NSS_CMSMessage_ContentLevelCount(env_cmsg); + for (i = 0; i < nlevels; i++) { + SECOidTag typetag; + cinfo = NSS_CMSMessage_ContentLevel(env_cmsg, i); + typetag = NSS_CMSContentInfo_GetContentTypeTag(cinfo); + if (typetag == SEC_OID_PKCS7_DATA) { + /* + * get the symmetric key + */ + encryptOptions->bulkalgtag = NSS_CMSContentInfo_GetContentEncAlgTag(cinfo); + encryptOptions->keysize = NSS_CMSContentInfo_GetBulkKeySize(cinfo); + encryptOptions->bulkkey = NSS_CMSContentInfo_GetBulkKey(cinfo); + rv = SECSuccess; + break; + } + } + if (i == nlevels) { + fprintf(stderr, "%s: could not retrieve enveloped data.", progName); + } + if (env_cmsg) + NSS_CMSMessage_Destroy(env_cmsg); + return rv; +} + +static NSSCMSMessage * +encrypted_data(struct encryptOptionsStr *encryptOptions) +{ + SECStatus rv = SECFailure; + NSSCMSMessage *cmsg = NULL; + NSSCMSContentInfo *cinfo; + NSSCMSEncryptedData *encd; + NSSCMSEncoderContext *ecx = NULL; + PLArenaPool *tmppoolp = NULL; + SECItem derOut = { 0, 0, 0 }; + /* arena for output */ + tmppoolp = PORT_NewArena(1024); + if (!tmppoolp) { + fprintf(stderr, "%s: out of memory.\n", progName); + return NULL; + } + /* + * create the message object + */ + cmsg = NSS_CMSMessage_Create(NULL); + if (cmsg == NULL) { + fprintf(stderr, "ERROR: cannot create CMS message.\n"); + goto loser; + } + /* + * build chain of objects: message->encryptedData->data + */ + if ((encd = NSS_CMSEncryptedData_Create(cmsg, encryptOptions->bulkalgtag, + encryptOptions->keysize)) + == NULL) { + fprintf(stderr, "ERROR: cannot create CMS encryptedData object.\n"); + goto loser; + } + cinfo = NSS_CMSMessage_GetContentInfo(cmsg); + if (NSS_CMSContentInfo_SetContent_EncryptedData(cmsg, cinfo, encd) + != SECSuccess) { + fprintf(stderr, "ERROR: cannot attach CMS encryptedData object.\n"); + goto loser; + } + cinfo = NSS_CMSEncryptedData_GetContentInfo(encd); + /* we're always passing data in, so the content is NULL */ + if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) + != SECSuccess) { + fprintf(stderr, "ERROR: cannot attach CMS data object.\n"); + goto loser; + } + ecx = NSS_CMSEncoder_Start(cmsg, NULL, NULL, &derOut, tmppoolp, NULL, NULL, + dkcb, encryptOptions->bulkkey, NULL, NULL); + if (!ecx) { + fprintf(stderr, "%s: cannot create encoder context.\n", progName); + goto loser; + } + rv = NSS_CMSEncoder_Update(ecx, (char *)encryptOptions->input->data, + encryptOptions->input->len); + if (rv) { + fprintf(stderr, "%s: failed to add data to encoder.\n", progName); + goto loser; + } + rv = NSS_CMSEncoder_Finish(ecx); + if (rv) { + fprintf(stderr, "%s: failed to encrypt data.\n", progName); + goto loser; + } + fwrite(derOut.data, derOut.len, 1, encryptOptions->outfile); + /* + if (bulkkey) + PK11_FreeSymKey(bulkkey); + */ + if (tmppoolp) + PORT_FreeArena(tmppoolp, PR_FALSE); + return cmsg; +loser: + /* + if (bulkkey) + PK11_FreeSymKey(bulkkey); + */ + if (tmppoolp) + PORT_FreeArena(tmppoolp, PR_FALSE); + if (cmsg) + NSS_CMSMessage_Destroy(cmsg); + return NULL; +} + +static NSSCMSMessage * +signed_data_certsonly(struct certsonlyOptionsStr *certsonlyOptions) +{ + NSSCMSMessage *cmsg = NULL; + NSSCMSContentInfo *cinfo; + NSSCMSSignedData *sigd; + CERTCertificate **certs = NULL; + CERTCertDBHandle *dbhandle; + PLArenaPool *tmppoolp = NULL; + int i = 0, cnt; + dbhandle = certsonlyOptions->options->certHandle; + if ((cnt = nss_CMSArray_Count((void**)certsonlyOptions->recipients)) == 0) { + fprintf(stderr, + "ERROR: please indicate the nickname of a certificate to sign with.\n"); + goto loser; + } + if ((tmppoolp = PORT_NewArena (1024)) == NULL) { + fprintf(stderr, "ERROR: out of memory.\n"); + goto loser; + } + if ((certs = + (CERTCertificate **)PORT_ArenaZAlloc(tmppoolp, + (cnt+1)*sizeof(CERTCertificate*))) + == NULL) { + fprintf(stderr, "ERROR: out of memory.\n"); + goto loser; + } + for (i=0; certsonlyOptions->recipients[i] != NULL; i++) { + if ((certs[i] = + CERT_FindCertByNicknameOrEmailAddr(dbhandle, + certsonlyOptions->recipients[i])) + == NULL) { + SECU_PrintError(progName, "cannot find certificate for \"%s\"", + certsonlyOptions->recipients[i]); + i=0; + goto loser; + } + } + certs[i] = NULL; + i=0; + /* + * create the message object + */ + cmsg = NSS_CMSMessage_Create(NULL); + if (cmsg == NULL) { + fprintf(stderr, "ERROR: cannot create CMS message.\n"); + goto loser; + } + /* + * build chain of objects: message->signedData->data + */ + if ((sigd = NSS_CMSSignedData_CreateCertsOnly(cmsg, certs[0], PR_TRUE)) + == NULL) { + fprintf(stderr, "ERROR: cannot create CMS signedData object.\n"); + goto loser; + } + CERT_DestroyCertificate(certs[0]); + for (i=1; i<cnt; i++) { + if (NSS_CMSSignedData_AddCertChain(sigd, certs[i])) { + fprintf(stderr, "ERROR: cannot add cert chain for \"%s\".\n", + certsonlyOptions->recipients[i]); + goto loser; + } + CERT_DestroyCertificate(certs[i]); + } + cinfo = NSS_CMSMessage_GetContentInfo(cmsg); + if (NSS_CMSContentInfo_SetContent_SignedData(cmsg, cinfo, sigd) + != SECSuccess) { + fprintf(stderr, "ERROR: cannot attach CMS signedData object.\n"); + goto loser; + } + cinfo = NSS_CMSSignedData_GetContentInfo(sigd); + if (NSS_CMSContentInfo_SetContent_Data(cmsg, cinfo, NULL, PR_FALSE) + != SECSuccess) { + fprintf(stderr, "ERROR: cannot attach CMS data object.\n"); + goto loser; + } + if (tmppoolp) + PORT_FreeArena(tmppoolp, PR_FALSE); + return cmsg; +loser: + if (certs) { + for (; i<cnt; i++) { + CERT_DestroyCertificate(certs[i]); + } + } + if (cmsg) + NSS_CMSMessage_Destroy(cmsg); + if (tmppoolp) + PORT_FreeArena(tmppoolp, PR_FALSE); + return NULL; +} + +typedef enum { UNKNOWN, DECODE, SIGN, ENCRYPT, ENVELOPE, CERTSONLY } Mode; + +int +main(int argc, char **argv) +{ + FILE *outFile; + NSSCMSMessage *cmsg = NULL; + PRFileDesc *inFile; + PLOptState *optstate; + PLOptStatus status; + Mode mode = UNKNOWN; + PK11PasswordFunc pwcb; + void *pwcb_arg; + struct decodeOptionsStr decodeOptions = { 0 }; + struct signOptionsStr signOptions = { 0 }; + struct envelopeOptionsStr envelopeOptions = { 0 }; + struct certsonlyOptionsStr certsonlyOptions = { 0 }; + struct encryptOptionsStr encryptOptions = { 0 }; + struct optionsStr options = { 0 }; + int exitstatus; + static char *ptrarray[128] = { 0 }; + int nrecipients = 0; + char *str, *tok; + char *envFileName; + SECItem input = { 0, 0, 0}; + SECItem output = { 0, 0, 0}; + SECItem dummy = { 0, 0, 0 }; + SECItem envmsg = { 0, 0, 0 }; + SECStatus rv; + + progName = strrchr(argv[0], '/'); + if (!progName) + progName = strrchr(argv[0], '\\'); + progName = progName ? progName+1 : argv[0]; + + inFile = PR_STDIN; + outFile = stdout; + envFileName = NULL; + mode = UNKNOWN; + decodeOptions.contentFile = NULL; + decodeOptions.suppressContent = PR_FALSE; + decodeOptions.headerLevel = -1; + options.certUsage = certUsageEmailSigner; + options.password = NULL; + signOptions.nickname = NULL; + signOptions.detached = PR_FALSE; + signOptions.signingTime = PR_FALSE; + signOptions.smimeProfile = PR_FALSE; + signOptions.encryptionKeyPreferenceNick = NULL; + signOptions.hashAlgTag = SEC_OID_SHA1; + envelopeOptions.recipients = NULL; + encryptOptions.recipients = NULL; + encryptOptions.envmsg = NULL; + encryptOptions.envFile = NULL; + encryptOptions.bulkalgtag = SEC_OID_UNKNOWN; + encryptOptions.bulkkey = NULL; + encryptOptions.keysize = -1; + + /* + * Parse command line arguments + */ + optstate = PL_CreateOptState(argc, argv, + "CDEGH:N:OPSTY:c:d:e:h:i:no:p:r:s:u:v"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case 'C': + mode = ENCRYPT; + break; + case 'D': + mode = DECODE; + break; + case 'E': + mode = ENVELOPE; + break; + case 'G': + if (mode != SIGN) { + fprintf(stderr, + "%s: option -G only supported with option -S.\n", + progName); + Usage(progName); + exit(1); + } + signOptions.signingTime = PR_TRUE; + break; + case 'H': + if (mode != SIGN) { + fprintf(stderr, + "%s: option -n only supported with option -D.\n", + "%s: option -H only supported with option -S.\n", + progName); + Usage(progName); + exit(1); + } + decodeOptions.suppressContent = PR_TRUE; + if (!strcmp(optstate->value, "MD2")) + signOptions.hashAlgTag = SEC_OID_MD2; + else if (!strcmp(optstate->value, "MD4")) + signOptions.hashAlgTag = SEC_OID_MD4; + else if (!strcmp(optstate->value, "MD5")) + signOptions.hashAlgTag = SEC_OID_MD5; + else if (!strcmp(optstate->value, "SHA1")) + signOptions.hashAlgTag = SEC_OID_SHA1; + else if (!strcmp(optstate->value, "SHA256")) + signOptions.hashAlgTag = SEC_OID_SHA256; + else if (!strcmp(optstate->value, "SHA384")) + signOptions.hashAlgTag = SEC_OID_SHA384; + else if (!strcmp(optstate->value, "SHA512")) + signOptions.hashAlgTag = SEC_OID_SHA512; + else { + fprintf(stderr, + "%s: -H requires one of MD2,MD4,MD5,SHA1,SHA256,SHA384,SHA512\n", + progName); + exit(1); + } + break; + case 'N': + if (mode != SIGN) { + fprintf(stderr, + "%s: option -N only supported with option -S.\n", + progName); + Usage(progName); + exit(1); + } + signOptions.nickname = strdup(optstate->value); + break; + case 'O': + mode = CERTSONLY; + break; + case 'P': + if (mode != SIGN) { + fprintf(stderr, + "%s: option -P only supported with option -S.\n", + progName); + Usage(progName); + exit(1); + } + signOptions.smimeProfile = PR_TRUE; + break; + case 'S': + mode = SIGN; + break; + case 'T': + if (mode != SIGN) { + fprintf(stderr, + "%s: option -T only supported with option -S.\n", + progName); + Usage(progName); + exit(1); + } + signOptions.detached = PR_TRUE; + break; + case 'Y': + if (mode != SIGN) { + fprintf(stderr, + "%s: option -Y only supported with option -S.\n", + progName); + Usage(progName); + exit(1); + } + signOptions.encryptionKeyPreferenceNick = strdup(optstate->value); + break; + + case 'c': + if (mode != DECODE) { + fprintf(stderr, + "%s: option -c only supported with option -D.\n", + progName); + Usage(progName); + exit(1); + } + if ((decodeOptions.contentFile = + PR_Open(optstate->value, PR_RDONLY, 006600)) == NULL) { + fprintf(stderr, "%s: unable to open \"%s\" for reading.\n", + progName, optstate->value); + exit(1); + } + break; + case 'd': + SECU_ConfigDirectory(optstate->value); + break; + case 'e': + envFileName = strdup(optstate->value); + encryptOptions.envFile = PR_Open(envFileName, PR_RDONLY, 00660); + break; + + case 'h': + if (mode != DECODE) { + fprintf(stderr, + "%s: option -h only supported with option -D.\n", + progName); + Usage(progName); + exit(1); + } + decodeOptions.headerLevel = atoi(optstate->value); + if (decodeOptions.headerLevel < 0) { + fprintf(stderr, "option -h cannot have a negative value.\n"); + exit(1); + } + break; + case 'i': + inFile = PR_Open(optstate->value, PR_RDONLY, 00660); + if (inFile == NULL) { + fprintf(stderr, "%s: unable to open \"%s\" for reading\n", + progName, optstate->value); + exit(1); + } + break; + + case 'n': + if (mode != DECODE) { + fprintf(stderr, + "%s: option -n only supported with option -D.\n", + progName); + Usage(progName); + exit(1); + } + decodeOptions.suppressContent = PR_TRUE; + break; + case 'o': + outFile = fopen(optstate->value, "wb"); + if (outFile == NULL) { + fprintf(stderr, "%s: unable to open \"%s\" for writing\n", + progName, optstate->value); + exit(1); + } + break; + case 'p': + if (!optstate->value) { + fprintf(stderr, "%s: option -p must have a value.\n", progName); + Usage(progName); + exit(1); + } + + options.password = strdup(optstate->value); + break; + + case 'r': + if (!optstate->value) { + fprintf(stderr, "%s: option -r must have a value.\n", progName); + Usage(progName); + exit(1); + } + envelopeOptions.recipients = ptrarray; + str = (char *)optstate->value; + do { + tok = strchr(str, ','); + if (tok) *tok = '\0'; + envelopeOptions.recipients[nrecipients++] = strdup(str); + if (tok) str = tok + 1; + } while (tok); + envelopeOptions.recipients[nrecipients] = NULL; + encryptOptions.recipients = envelopeOptions.recipients; + certsonlyOptions.recipients = envelopeOptions.recipients; + break; + + case 'u': { + int usageType; + + usageType = atoi (strdup(optstate->value)); + if (usageType < certUsageSSLClient || usageType > certUsageAnyCA) + return -1; + options.certUsage = (SECCertUsage)usageType; + break; + } + case 'v': + cms_verbose = 1; + break; + + } + } + if (status == PL_OPT_BAD) + Usage(progName); + PL_DestroyOptState(optstate); + + if (mode == UNKNOWN) + Usage(progName); + + if (mode != CERTSONLY) + SECU_FileToItem(&input, inFile); + if (inFile != PR_STDIN) + PR_Close(inFile); + if (cms_verbose) { + fprintf(stderr, "received commands\n"); + } + + /* Call the libsec initialization routines */ + PR_Init(PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + rv = NSS_InitReadWrite(SECU_ConfigDirectory(NULL)); + if (SECSuccess != rv) { + SECU_PrintError(progName, "NSS_Init failed"); + exit(1); + } + if (cms_verbose) { + fprintf(stderr, "NSS has been initialized.\n"); + } + options.certHandle = CERT_GetDefaultCertDB(); + if (!options.certHandle) { + SECU_PrintError(progName, "No default cert DB"); + exit(1); + } + if (cms_verbose) { + fprintf(stderr, "Got default certdb\n"); + } + +#if defined(_WIN32) + if (outFile == stdout) { + /* If we're going to write binary data to stdout, we must put stdout + ** into O_BINARY mode or else outgoing \n's will become \r\n's. + */ + int smrv = _setmode(_fileno(stdout), _O_BINARY); + if (smrv == -1) { + fprintf(stderr, + "%s: Cannot change stdout to binary mode. Use -o option instead.\n", + progName); + return smrv; + } + } +#endif + + exitstatus = 0; + switch (mode) { + case DECODE: + decodeOptions.options = &options; + if (encryptOptions.envFile) { + /* Decoding encrypted-data, so get the bulkkey from an + * enveloped-data message. + */ + SECU_FileToItem(&envmsg, encryptOptions.envFile); + decodeOptions.options = &options; + encryptOptions.envmsg = decode(NULL, &dummy, &envmsg, + &decodeOptions); + if (!encryptOptions.envmsg) { + SECU_PrintError(progName, "problem decoding env msg"); + exitstatus = 1; + break; + } + rv = get_enc_params(&encryptOptions); + decodeOptions.dkcb = dkcb; + decodeOptions.bulkkey = encryptOptions.bulkkey; + } + cmsg = decode(outFile, &output, &input, &decodeOptions); + if (!cmsg) { + SECU_PrintError(progName, "problem decoding"); + exitstatus = 1; + } + fwrite(output.data, output.len, 1, outFile); + break; + case SIGN: + signOptions.options = &options; + cmsg = signed_data(&signOptions); + if (!cmsg) { + SECU_PrintError(progName, "problem signing"); + exitstatus = 1; + } + break; + case ENCRYPT: + if (!envFileName) { + fprintf(stderr, "%s: you must specify an envelope file with -e.\n", + progName); + exit(1); + } + encryptOptions.options = &options; + encryptOptions.input = &input; + encryptOptions.outfile = outFile; + if (!encryptOptions.envFile) { + encryptOptions.envFile = PR_Open(envFileName, + PR_WRONLY|PR_CREATE_FILE, 00660); + if (!encryptOptions.envFile) { + fprintf(stderr, "%s: failed to create file %s.\n", progName, + envFileName); + exit(1); + } + } else { + SECU_FileToItem(&envmsg, encryptOptions.envFile); + decodeOptions.options = &options; + encryptOptions.envmsg = decode(NULL, &dummy, &envmsg, + &decodeOptions); + if (encryptOptions.envmsg == NULL) { + SECU_PrintError(progName, "problem decrypting env msg"); + exitstatus = 1; + break; + } + } + /* decode an enveloped-data message to get the bulkkey (create + * a new one if neccessary) + */ + rv = get_enc_params(&encryptOptions); + /* create the encrypted-data message */ + cmsg = encrypted_data(&encryptOptions); + if (!cmsg) { + SECU_PrintError(progName, "problem encrypting"); + exitstatus = 1; + } + if (encryptOptions.bulkkey) { + PK11_FreeSymKey(encryptOptions.bulkkey); + encryptOptions.bulkkey = NULL; + } + break; + case ENVELOPE: + envelopeOptions.options = &options; + cmsg = enveloped_data(&envelopeOptions); + if (!cmsg) { + SECU_PrintError(progName, "problem enveloping"); + exitstatus = 1; + } + break; + case CERTSONLY: + certsonlyOptions.options = &options; + cmsg = signed_data_certsonly(&certsonlyOptions); + if (!cmsg) { + SECU_PrintError(progName, "problem with certs-only"); + exitstatus = 1; + } + break; + default: + fprintf(stderr, "One of options -D, -S or -E must be set.\n"); + Usage(progName); + exitstatus = 1; + } + if ( (mode == SIGN || mode == ENVELOPE || mode == CERTSONLY) + && (!exitstatus) ) { + PLArenaPool *arena = PORT_NewArena(1024); + NSSCMSEncoderContext *ecx; + SECItem output = { 0, 0, 0 }; + secuPWData pwdata = { PW_NONE, 0 }; + + if (!arena) { + fprintf(stderr, "%s: out of memory.\n", progName); + exit(1); + } + + if (options.password) + { + pwdata.source = PW_PLAINTEXT; + pwdata.data = options.password; + } + pwcb = SECU_GetModulePassword; + pwcb_arg = (void *)&pwdata; + + if (cms_verbose) { + fprintf(stderr, "cmsg [%p]\n", cmsg); + fprintf(stderr, "arena [%p]\n", arena); + if (pwcb_arg) + fprintf(stderr, "password [%s]\n", (char *)pwcb_arg); + else + fprintf(stderr, "password [NULL]\n"); + } + ecx = NSS_CMSEncoder_Start(cmsg, + NULL, NULL, /* DER output callback */ + &output, arena, /* destination storage */ + pwcb, pwcb_arg, /* password callback */ + NULL, NULL, /* decrypt key callback */ + NULL, NULL ); /* detached digests */ + if (!ecx) { + fprintf(stderr, "%s: cannot create encoder context.\n", progName); + exit(1); + } + if (cms_verbose) { + fprintf(stderr, "input len [%d]\n", input.len); + { unsigned int j; + for(j=0;j<input.len;j++) + fprintf(stderr, "%2x%c", input.data[j], (j>0&&j%35==0)?'\n':' '); + } + } + if (input.len > 0) { /* skip if certs-only (or other zero content) */ + rv = NSS_CMSEncoder_Update(ecx, (char *)input.data, input.len); + if (rv) { + fprintf(stderr, + "%s: failed to add data to encoder.\n", progName); + exit(1); + } + } + rv = NSS_CMSEncoder_Finish(ecx); + if (rv) { + SECU_PrintError(progName, "failed to encode data"); + exit(1); + } + + if (cms_verbose) { + fprintf(stderr, "encoding passed\n"); + } + /*PR_Write(output.data, output.len);*/ + fwrite(output.data, output.len, 1, outFile); + if (cms_verbose) { + fprintf(stderr, "wrote to file\n"); + } + PORT_FreeArena(arena, PR_FALSE); + } + if (cmsg) + NSS_CMSMessage_Destroy(cmsg); + if (outFile != stdout) + fclose(outFile); + + if (decodeOptions.contentFile) + PR_Close(decodeOptions.contentFile); + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + exit(exitstatus); +} diff --git a/security/nss/cmd/smimetools/manifest.mn b/security/nss/cmd/smimetools/manifest.mn new file mode 100644 index 000000000..552cfec7d --- /dev/null +++ b/security/nss/cmd/smimetools/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +MODULE = nss + +CSRCS = cmsutil.c + +MYLIB = $(DIST)/lib/libsmime.a + +REQUIRES = seccmd dbm + +PROGRAM = cmsutil +SCRIPTS = smime diff --git a/security/nss/cmd/smimetools/rules.mk b/security/nss/cmd/smimetools/rules.mk new file mode 100644 index 000000000..51e0baaed --- /dev/null +++ b/security/nss/cmd/smimetools/rules.mk @@ -0,0 +1,37 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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$ +# + +install:: + $(INSTALL) -m 755 $(SCRIPTS) $(SOURCE_BIN_DIR) diff --git a/security/nss/cmd/smimetools/smime b/security/nss/cmd/smimetools/smime new file mode 100755 index 000000000..d23a912ed --- /dev/null +++ b/security/nss/cmd/smimetools/smime @@ -0,0 +1,576 @@ +#!/usr/local/bin/perl + +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. + +# +# smime.pl - frontend for S/MIME message generation and parsing +# +# $Id$ +# + +use Getopt::Std; + +@boundarychars = ( "0" .. "9", "A" .. "F" ); + +# path to cmsutil +$cmsutilpath = "cmsutil"; + +# +# Thanks to Gisle Aas <gisle@aas.no> for the base64 functions +# originally taken from MIME-Base64-2.11 at www.cpan.org +# +sub encode_base64($) +{ + my $res = ""; + pos($_[0]) = 0; # ensure start at the beginning + while ($_[0] =~ /(.{1,45})/gs) { + $res .= substr(pack('u', $1), 1); # get rid of length byte after packing + chop($res); + } + $res =~ tr|` -_|AA-Za-z0-9+/|; + # fix padding at the end + my $padding = (3 - length($_[0]) % 3) % 3; + $res =~ s/.{$padding}$/'=' x $padding/e if $padding; + # break encoded string into lines of no more than 76 characters each + $res =~ s/(.{1,76})/$1\n/g; + $res; +} + +sub decode_base64($) +{ + local($^W) = 0; # unpack("u",...) gives bogus warning in 5.00[123] + + my $str = shift; + my $res = ""; + + $str =~ tr|A-Za-z0-9+=/||cd; # remove non-base64 chars + if (length($str) % 4) { + require Carp; + Carp::carp("Length of base64 data not a multiple of 4") + } + $str =~ s/=+$//; # remove padding + $str =~ tr|A-Za-z0-9+/| -_|; # convert to uuencoded format + while ($str =~ /(.{1,60})/gs) { + my $len = chr(32 + length($1)*3/4); # compute length byte + $res .= unpack("u", $len . $1 ); # uudecode + } + $res; +} + +# +# parse headers into a hash +# +# %headers = parseheaders($headertext); +# +sub parseheaders($) +{ + my ($headerdata) = @_; + my $hdr; + my %hdrhash; + my $hdrname; + my $hdrvalue; + my @hdrvalues; + my $subhdrname; + my $subhdrvalue; + + # the expression in split() correctly handles continuation lines + foreach $hdr (split(/\n(?=\S)/, $headerdata)) { + $hdr =~ s/\r*\n\s+/ /g; # collapse continuation lines + ($hdrname, $hdrvalue) = $hdr =~ m/^(\S+):\s+(.*)$/; + + # ignore non-headers (or should we die horribly?) + next unless (defined($hdrname)); + $hdrname =~ tr/A-Z/a-z/; # lowercase the header name + @hdrvalues = split(/\s*;\s*/, $hdrvalue); # split header values (XXXX quoting) + + # there is guaranteed to be at least one value + $hdrvalue = shift @hdrvalues; + if ($hdrvalue =~ /^\s*\"(.*)\"\s*$/) { # strip quotes if there + $hdrvalue = $1; + } + + $hdrhash{$hdrname}{MAIN} = $hdrvalue; + # print "XXX $hdrname = $hdrvalue\n"; + + # deal with additional name-value pairs + foreach $hdrvalue (@hdrvalues) { + ($subhdrname, $subhdrvalue) = $hdrvalue =~ m/^(\S+)\s*=\s*(.*)$/; + # ignore non-name-value pairs (or should we die?) + next unless (defined($subhdrname)); + $subhdrname =~ tr/A-Z/a-z/; + if ($subhdrvalue =~ /^\s*\"(.*)\"\s*$/) { # strip quotes if there + $subhdrvalue = $1; + } + $hdrhash{$hdrname}{$subhdrname} = $subhdrvalue; + } + + } + return %hdrhash; +} + +# +# encryptentity($entity, $options) - encrypt an S/MIME entity, +# creating a new application/pkcs7-smime entity +# +# entity - string containing entire S/MIME entity to encrypt +# options - options for cmsutil +# +# this will generate and return a new application/pkcs7-smime entity containing +# the enveloped input entity. +# +sub encryptentity($$) +{ + my ($entity, $cmsutiloptions) = @_; + my $out = ""; + my $boundary; + + $tmpencfile = "/tmp/encryptentity.$$"; + + # + # generate a random boundary string + # + $boundary = "------------ms" . join("", @boundarychars[map{rand @boundarychars }( 1 .. 24 )]); + + # + # tell cmsutil to generate a enveloped CMS message using our data + # + open(CMS, "|$cmsutilpath -E $cmsutiloptions -o $tmpencfile") or die "ERROR: cannot pipe to cmsutil"; + print CMS $entity; + unless (close(CMS)) { + print STDERR "ERROR: encryption failed.\n"; + unlink($tmpsigfile); + exit 1; + } + + $out = "Content-Type: application/pkcs7-mime; smime-type=enveloped-data; name=smime.p7m\n"; + $out .= "Content-Transfer-Encoding: base64\n"; + $out .= "Content-Disposition: attachment; filename=smime.p7m\n"; + $out .= "\n"; # end of entity header + + open (ENC, $tmpencfile) or die "ERROR: cannot find newly generated encrypted content"; + local($/) = undef; # slurp whole file + $out .= encode_base64(<ENC>), "\n"; # entity body is base64-encoded CMS message + close(ENC); + + unlink($tmpencfile); + + $out; +} + +# +# signentity($entity, $options) - sign an S/MIME entity +# +# entity - string containing entire S/MIME entity to sign +# options - options for cmsutil +# +# this will generate and return a new multipart/signed entity consisting +# of the canonicalized original content, plus a signature block. +# +sub signentity($$) +{ + my ($entity, $cmsutiloptions) = @_; + my $out = ""; + my $boundary; + + $tmpsigfile = "/tmp/signentity.$$"; + + # + # generate a random boundary string + # + $boundary = "------------ms" . join("", @boundarychars[map{rand @boundarychars }( 1 .. 24 )]); + + # + # tell cmsutil to generate a signed CMS message using the canonicalized data + # The signedData has detached content (-T) and includes a signing time attribute (-G) + # + # if we do not provide a password on the command line, here's where we would be asked for it + # + open(CMS, "|$cmsutilpath -S -T -G $cmsutiloptions -o $tmpsigfile") or die "ERROR: cannot pipe to cmsutil"; + print CMS $entity; + unless (close(CMS)) { + print STDERR "ERROR: signature generation failed.\n"; + unlink($tmpsigfile); + exit 1; + } + + open (SIG, $tmpsigfile) or die "ERROR: cannot find newly generated signature"; + + # + # construct a new multipart/signed MIME entity consisting of the original content and + # the signature + # + # (we assume that cmsutil generates a SHA1 digest) + $out .= "Content-Type: multipart/signed; protocol=\"application/pkcs7-signature\"; micalg=sha1; boundary=\"${boundary}\"\n"; + $out .= "\n"; # end of entity header + $out .= "This is a cryptographically signed message in MIME format.\n"; # explanatory comment + $out .= "\n--${boundary}\n"; + $out .= $entity; + $out .= "\n--${boundary}\n"; + $out .= "Content-Type: application/pkcs7-signature; name=smime.p7s\n"; + $out .= "Content-Transfer-Encoding: base64\n"; + $out .= "Content-Disposition: attachment; filename=smime.p7s\n"; + $out .= "Content-Description: S/MIME Cryptographic Signature\n"; + $out .= "\n"; # end of signature subentity header + + local($/) = undef; # slurp whole file + $out .= encode_base64(<SIG>); # append base64-encoded signature + $out .= "\n--${boundary}--\n"; + + close(SIG); + unlink($tmpsigfile); + + $out; +} + +sub usage { + print STDERR "usage: smime [options]\n"; + print STDERR " options:\n"; + print STDERR " -S nick generate signed message, use certificate named \"nick\"\n"; + print STDERR " -p passwd use \"passwd\" as security module password\n"; + print STDERR " -E rec1[,rec2...] generate encrypted message for recipients\n"; + print STDERR " -D decode a S/MIME message\n"; + print STDERR " -p passwd use \"passwd\" as security module password\n"; + print STDERR " (required for decrypting only)\n"; + print STDERR " -C pathname set pathname of \"cmsutil\"\n"; + print STDERR " -d directory set directory containing certificate db\n"; + print STDERR " (default: ~/.netscape)\n"; + print STDERR "\nWith -S or -E, smime will take a regular RFC822 message or MIME entity\n"; + print STDERR "on stdin and generate a signed or encrypted S/MIME message with the same\n"; + print STDERR "headers and content from it. The output can be used as input to a MTA.\n"; + print STDERR "-D causes smime to strip off all S/MIME layers if possible and output\n"; + print STDERR "the \"inner\" message.\n"; +} + +# +# start of main procedures +# + +# +# process command line options +# +unless (getopts('S:E:p:d:C:D')) { + usage(); + exit 1; +} + +unless (defined($opt_S) or defined($opt_E) or defined($opt_D)) { + print STDERR "ERROR: -S and/or -E, or -D must be specified.\n"; + usage(); + exit 1; +} + +$signopts = ""; +$encryptopts = ""; +$decodeopts = ""; + +# pass -d option along +if (defined($opt_d)) { + $signopts .= "-d \"$opt_d\" "; + $encryptopts .= "-d \"$opt_d\" "; + $decodeopts .= "-d \"$opt_d\" "; +} + +if (defined($opt_S)) { + $signopts .= "-N \"$opt_S\" "; +} + +if (defined($opt_p)) { + $signopts .= "-p \"$opt_p\" "; + $decodeopts .= "-p \"$opt_p\" "; +} + +if (defined($opt_E)) { + @recipients = split(",", $opt_E); + $encryptopts .= "-r "; + $encryptopts .= join (" -r ", @recipients); +} + +if (defined($opt_C)) { + $cmsutilpath = $opt_C; +} + +# +# split headers into mime entity headers and RFC822 headers +# The RFC822 headers are preserved and stay on the outer layer of the message +# +$rfc822headers = ""; +$mimeheaders = ""; +$mimebody = ""; +$skippedheaders = ""; +while (<STDIN>) { + last if (/^$/); + if (/^content-\S+: /i) { + $lastref = \$mimeheaders; + } elsif (/^mime-version: /i) { + $lastref = \$skippedheaders; # skip it + } elsif (/^\s/) { + ; + } else { + $lastref = \$rfc822headers; + } + $$lastref .= $_; +} + +# +# if there are no MIME entity headers, generate some default ones +# +if ($mimeheaders eq "") { + $mimeheaders .= "Content-Type: text/plain; charset=us-ascii\n"; + $mimeheaders .= "Content-Transfer-Encoding: 7bit\n"; +} + +# +# slurp in the entity body +# +$saveRS = $/; +$/ = undef; +$mimebody = <STDIN>; +$/ = $saveRS; +chomp($mimebody); + +if (defined $opt_D) { + # + # decode + # + # possible options would be: + # - strip off only one layer + # - strip off outer signature (if present) + # - just print information about the structure of the message + # - strip n layers, then dump DER of CMS message + + $layercounter = 1; + + while (1) { + %hdrhash = parseheaders($mimeheaders); + unless (exists($hdrhash{"content-type"}{MAIN})) { + print STDERR "ERROR: no content type header found in MIME entity\n"; + last; # no content-type - we're done + } + + $contenttype = $hdrhash{"content-type"}{MAIN}; + if ($contenttype eq "application/pkcs7-mime") { + # + # opaque-signed or enveloped message + # + unless (exists($hdrhash{"content-type"}{"smime-type"})) { + print STDERR "ERROR: no smime-type attribute in application/pkcs7-smime entity.\n"; + last; + } + $smimetype = $hdrhash{"content-type"}{"smime-type"}; + if ($smimetype eq "signed-data" or $smimetype eq "enveloped-data") { + # it's verification or decryption time! + + # can handle only base64 encoding for now + # all other encodings are treated as binary (8bit) + if ($hdrhash{"content-transfer-encoding"}{MAIN} eq "base64") { + $mimebody = decode_base64($mimebody); + } + + # if we need to dump the DER, we would do it right here + + # now write the DER + $tmpderfile = "/tmp/der.$$"; + open(TMP, ">$tmpderfile") or die "ERROR: cannot write signature data to temporary file"; + print TMP $mimebody; + unless (close(TMP)) { + print STDERR "ERROR: writing signature data to temporary file.\n"; + unlink($tmpderfile); + exit 1; + } + + $mimeheaders = ""; + open(TMP, "$cmsutilpath -D $decodeopts -h $layercounter -i $tmpderfile |") or die "ERROR: cannot open pipe to cmsutil"; + $layercounter++; + while (<TMP>) { + last if (/^\r?$/); # empty lines mark end of header + if (/^SMIME: /) { # add all SMIME info to the rfc822 hdrs + $lastref = \$rfc822headers; + } elsif (/^\s/) { + ; # continuation lines go to the last dest + } else { + $lastref = \$mimeheaders; # all other headers are mime headers + } + $$lastref .= $_; + } + # slurp in rest of the data to $mimebody + $saveRS = $/; $/ = undef; $mimebody = <TMP>; $/ = $saveRS; + close(TMP); + + unlink($tmpderfile); + + } else { + print STDERR "ERROR: unknown smime-type \"$smimetype\" in application/pkcs7-smime entity.\n"; + last; + } + } elsif ($contenttype eq "multipart/signed") { + # + # clear signed message + # + unless (exists($hdrhash{"content-type"}{"protocol"})) { + print STDERR "ERROR: content type has no protocol attribute in multipart/signed entity.\n"; + last; + } + if ($hdrhash{"content-type"}{"protocol"} ne "application/pkcs7-signature") { + # we cannot handle this guy + print STDERR "ERROR: unknown protocol \"", $hdrhash{"content-type"}{"protocol"}, + "\" in multipart/signed entity.\n"; + last; + } + unless (exists($hdrhash{"content-type"}{"boundary"})) { + print STDERR "ERROR: no boundary attribute in multipart/signed entity.\n"; + last; + } + $boundary = $hdrhash{"content-type"}{"boundary"}; + + # split $mimebody along \n--$boundary\n - gets you four parts + # first (0), any comments the sending agent might have put in + # second (1), the message itself + # third (2), the signature as a mime entity + # fourth (3), trailing data (there shouldn't be any) + + @multiparts = split(/\r?\n--$boundary(?:--)?\r?\n/, $mimebody); + + # + # parse the signature headers + ($submimeheaders, $submimebody) = split(/^$/m, $multiparts[2]); + %sighdrhash = parseheaders($submimeheaders); + unless (exists($sighdrhash{"content-type"}{MAIN})) { + print STDERR "ERROR: signature entity has no content type.\n"; + last; + } + if ($sighdrhash{"content-type"}{MAIN} ne "application/pkcs7-signature") { + # we cannot handle this guy + print STDERR "ERROR: unknown content type \"", $sighdrhash{"content-type"}{MAIN}, + "\" in signature entity.\n"; + last; + } + if ($sighdrhash{"content-transfer-encoding"}{MAIN} eq "base64") { + $submimebody = decode_base64($submimebody); + } + + # we would dump the DER at this point + + $tmpsigfile = "/tmp/sig.$$"; + open(TMP, ">$tmpsigfile") or die "ERROR: cannot write signature data to temporary file"; + print TMP $submimebody; + unless (close(TMP)) { + print STDERR "ERROR: writing signature data to temporary file.\n"; + unlink($tmpsigfile); + exit 1; + } + + $tmpmsgfile = "/tmp/msg.$$"; + open(TMP, ">$tmpmsgfile") or die "ERROR: cannot write message data to temporary file"; + print TMP $multiparts[1]; + unless (close(TMP)) { + print STDERR "ERROR: writing message data to temporary file.\n"; + unlink($tmpsigfile); + unlink($tmpmsgfile); + exit 1; + } + + $mimeheaders = ""; + open(TMP, "$cmsutilpath -D $decodeopts -h $layercounter -c $tmpmsgfile -i $tmpsigfile |") or die "ERROR: cannot open pipe to cmsutil"; + $layercounter++; + while (<TMP>) { + last if (/^\r?$/); + if (/^SMIME: /) { + $lastref = \$rfc822headers; + } elsif (/^\s/) { + ; + } else { + $lastref = \$mimeheaders; + } + $$lastref .= $_; + } + $saveRS = $/; $/ = undef; $mimebody = <TMP>; $/ = $saveRS; + close(TMP); + unlink($tmpsigfile); + unlink($tmpmsgfile); + + } else { + + # not a content type we know - we're done + last; + + } + } + + # so now we have the S/MIME parsing information in rfc822headers + # and the first mime entity we could not handle in mimeheaders and mimebody. + # dump 'em out and we're done. + print $rfc822headers; + print $mimeheaders . "\n" . $mimebody; + +} else { + + # + # encode (which is much easier than decode) + # + + $mimeentity = $mimeheaders . "\n" . $mimebody; + + # + # canonicalize inner entity (rudimentary yet) + # convert single LFs to CRLF + # if no Content-Transfer-Encoding header present: + # if 8 bit chars present, use Content-Transfer-Encoding: quoted-printable + # otherwise, use Content-Transfer-Encoding: 7bit + # + $mimeentity =~ s/\r*\n/\r\n/mg; + + # + # now do the wrapping + # we sign first, then encrypt because that's what Communicator needs + # + if (defined($opt_S)) { + $mimeentity = signentity($mimeentity, $signopts); + } + + if (defined($opt_E)) { + $mimeentity = encryptentity($mimeentity, $encryptopts); + } + + # + # XXX sign again to do triple wrapping (RFC2634) + # + + # + # now write out the RFC822 headers + # followed by the final $mimeentity + # + print $rfc822headers; + print "MIME-Version: 1.0 (NSS SMIME - http://www.mozilla.org/projects/security)\n"; # set up the flag + print $mimeentity; +} + +exit 0; diff --git a/security/nss/cmd/sslstrength/Makefile b/security/nss/cmd/sslstrength/Makefile new file mode 100644 index 000000000..8a0332d89 --- /dev/null +++ b/security/nss/cmd/sslstrength/Makefile @@ -0,0 +1,82 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +ifeq (,$(filter-out WINNT WIN95 WIN16,$(OS_TARGET))) # omits WINCE +ifndef BUILD_OPT +LDFLAGS += /subsystem:console /profile /debug /machine:I386 /incremental:no +OS_CFLAGS += -D_CONSOLE +endif +endif + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + +#include ../platlibs.mk + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +include ../platrules.mk + diff --git a/security/nss/cmd/sslstrength/manifest.mn b/security/nss/cmd/sslstrength/manifest.mn new file mode 100644 index 000000000..8b7cb7b0d --- /dev/null +++ b/security/nss/cmd/sslstrength/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +MODULE = nss + +EXPORTS = + +CSRCS = sslstrength.c \ + $(NULL) + +PROGRAM = sslstrength + +REQUIRES = dbm seccmd + +DEFINES += -DDLL_PREFIX=\"$(DLL_PREFIX)\" -DDLL_SUFFIX=\"$(DLL_SUFFIX)\" + +PACKAGE_FILES = sslstrength + +ARCHIVE_NAME = sslstrength diff --git a/security/nss/cmd/sslstrength/sslstr.cgi b/security/nss/cmd/sslstrength/sslstr.cgi new file mode 100644 index 000000000..ab6a1bff9 --- /dev/null +++ b/security/nss/cmd/sslstrength/sslstr.cgi @@ -0,0 +1,296 @@ +#!/usr/bin/perl +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + + +use CGI qw(:standard); + + + +# Replace this will the full path to the sslstrength executable. +$sslstrength = "./sslstrength"; + + +# Replace this with the name of this CGI. + +$sslcgi = "sslstr.cgi"; + + +$query = new CGI; + +print header; + +print "<HTML><HEAD> +<SCRIPT language='javascript'> + +function doexport(form) { + form.ssl2ciphers.options[0].selected=0; + form.ssl2ciphers.options[1].selected=0; + form.ssl2ciphers.options[2].selected=0; + form.ssl2ciphers.options[3].selected=0; + form.ssl2ciphers.options[4].selected=1; + form.ssl2ciphers.options[5].selected=1; + + form.ssl3ciphers.options[0].selected=1; + form.ssl3ciphers.options[1].selected=1; + form.ssl3ciphers.options[2].selected=0; + form.ssl3ciphers.options[3].selected=1; + form.ssl3ciphers.options[4].selected=1; + form.ssl3ciphers.options[5].selected=1; + form.ssl3ciphers.options[6].selected=0; + form.ssl3ciphers.options[7].selected=0; + + +} + +function dodomestic(form) { + form.ssl2ciphers.options[0].selected=1; + form.ssl2ciphers.options[1].selected=1; + form.ssl2ciphers.options[2].selected=1; + form.ssl2ciphers.options[3].selected=1; + form.ssl2ciphers.options[4].selected=1; + form.ssl2ciphers.options[5].selected=1; + + form.ssl3ciphers.options[0].selected=1; + form.ssl3ciphers.options[1].selected=1; + form.ssl3ciphers.options[2].selected=1; + form.ssl3ciphers.options[3].selected=1; + form.ssl3ciphers.options[4].selected=1; + form.ssl3ciphers.options[5].selected=1; + form.ssl3ciphers.options[6].selected=1; + form.ssl3ciphers.options[7].selected=1; + +} + +function doclearssl2(form) { + form.ssl2ciphers.options[0].selected=0; + form.ssl2ciphers.options[1].selected=0; + form.ssl2ciphers.options[2].selected=0; + form.ssl2ciphers.options[3].selected=0; + form.ssl2ciphers.options[4].selected=0; + form.ssl2ciphers.options[5].selected=0; +} + + +function doclearssl3(form) { + form.ssl3ciphers.options[0].selected=0; + form.ssl3ciphers.options[1].selected=0; + form.ssl3ciphers.options[2].selected=0; + form.ssl3ciphers.options[3].selected=0; + form.ssl3ciphers.options[4].selected=0; + form.ssl3ciphers.options[5].selected=0; + form.ssl3ciphers.options[6].selected=0; + form.ssl3ciphers.options[7].selected=0; + +} + +function dohost(form,hostname) { + form.host.value=hostname; + } + + + +</SCRIPT> +<TITLE>\n"; +print "SSLStrength\n"; +print "</TITLE></HEAD>\n"; + +print "<h1>SSLStrength</h1>\n"; + +if ($query->param('dotest')) { + print "Output from sslstrength: \n"; + print "<pre>\n"; + + $cs = ""; + + @ssl2ciphers = $query->param('ssl2ciphers'); + for $cipher (@ssl2ciphers) { + if ($cipher eq "SSL_EN_RC2_128_WITH_MD5") { $cs .= "a"; } + if ($cipher eq "SSL_EN_RC2_128_CBC_WITH_MD5") { $cs .= "b"; } + if ($cipher eq "SSL_EN_DES_192_EDE3_CBC_WITH_MD5") { $cs .= "c"; } + if ($cipher eq "SSL_EN_DES_64_CBC_WITH_MD5") { $cs .= "d"; } + if ($cipher eq "SSL_EN_RC4_128_EXPORT40_WITH_MD5") { $cs .= "e"; } + if ($cipher eq "SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5") { $cs .= "f"; } + } + + @ssl3ciphers = $query->param('ssl3ciphers'); + for $cipher (@ssl3ciphers) { + if ($cipher eq "SSL_RSA_WITH_RC4_128_MD5") { $cs .= "i"; } + if ($cipher eq "SSL_RSA_WITH_3DES_EDE_CBC_SHA") { $cs .= "j"; } + if ($cipher eq "SSL_RSA_WITH_DES_CBC_SHA") { $cs .= "k"; } + if ($cipher eq "SSL_RSA_EXPORT_WITH_RC4_40_MD5") { $cs .= "l"; } + if ($cipher eq "SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5") { $cs .= "m"; } + if ($cipher eq "SSL_RSA_WITH_NULL_MD5") { $cs .= "o"; } + if ($cipher eq "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA") { $cs .= "p"; } + if ($cipher eq "SSL_RSA_FIPS_WITH_DES_CBC_SHA") { $cs .= "q"; } + } + + $hs = $query->param('host'); + if ($hs eq "") { + print "</pre>You must specify a host to connect to.<br><br>\n"; + exit(0); + } + + $ps = $query->param('policy'); + + $cmdstring = "$sslstrength $hs policy=$ps ciphers=$cs"; + + print "running sslstrength:\n"; + print "$cmdstring\n"; + + $r = open(SSLS, "$cmdstring |"); + if ($r == 0) { + print "<pre>There was a problem starting $cmdstring<br><br>\n"; + exit(0); + } + while (<SSLS>) { + print "$_"; + } + close(SSLS); + + + print "</pre>\n"; + +} + +else { +print "<FORM method=post action=$sslcgi>\n"; +print "<hr> +<h2>Host Name</h2> +<TABLE BORDER=0 CELLPADDING=20> +<TR> +<TD> +Type hostname here:<br> +<input type=text name=host size=30> <br><br> +<TD> + <b>Or click these buttons to test some well-known servers</b><br> + <TABLE BORDER=0> + <TR> + <TD> + Export servers: + <TD> + <input type=button value='F-Tech' onclick=dohost(this.form,'strongbox.ftech.net')> + </TR> + <TR> + <TD> + Domestic servers: + <TD> + <input type=button value='Wells Fargo' onclick=dohost(this.form,'banking.wellsfargo.com')> + </TR> + <TR> + <TD> + Step-Up Servers + <TD> + <input type=button value='Barclaycard' onclick=dohost(this.form,'enigma.barclaycard.co.uk')> + <input type=button value='BBVnet' onclick=dohost(this.form,'www.bbvnet.com')> + <input type=button value='BHIF' onclick=dohost(this.form,'empresas.bhif.cl')> + </TR> + </TABLE> +</TR> +</TABLE> +<br> +<hr> +<br> +<h2>Encryption policy</h2> +<input type=radio name=policy VALUE=export onclick=doexport(this.form)> +Export<br> +<input type=radio name=policy VALUE=domestic CHECKED onclick=dodomestic(this.form)> +Domestic<br> +<br> +<hr> +<br> +<h2>Cipher Selection</h2> +(use ctrl to multi-select)<br> +<table> +<tr> +<td>SSL 2 Ciphers +<td> +<SELECT NAME=ssl2ciphers SIZE=6 MULTIPLE align=bottom> +<OPTION SELECTED>SSL_EN_RC4_128_WITH_MD5 +<OPTION SELECTED>SSL_EN_RC2_128_CBC_WITH_MD5 +<OPTION SELECTED>SSL_EN_DES_192_EDE3_CBC_WITH_MD5 +<OPTION SELECTED>SSL_EN_DES_64_CBC_WITH_MD5 +<OPTION SELECTED>SSL_EN_RC4_128_EXPORT40_WITH_MD5 +<OPTION SELECTED>SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5 +</SELECT> +<input type=button Value='Clear all' onclick = 'doclearssl2(this.form)'> +</tr> +<tr> +<td>SSL3 Ciphers +<td> +<SELECT NAME=ssl3ciphers SIZE=8 MULTIPLE> +<OPTION SELECTED>SSL_RSA_WITH_RC4_128_MD5 +<OPTION SELECTED>SSL_RSA_WITH_3DES_EDE_CBC_SHA +<OPTION SELECTED>SSL_RSA_WITH_DES_CBC_SHA +<OPTION SELECTED>SSL_RSA_EXPORT_WITH_RC4_40_MD5 +<OPTION SELECTED>SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 +<OPTION SELECTED>SSL_RSA_WITH_NULL_MD5 +<OPTION SELECTED>SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA +<OPTION SELECTED>SSL_RSA_FIPS_WITH_DES_CBC_SHA +</SELECT> +<input type=button value='Clear all' onclick = 'doclearssl3(this.form)'> + +<TD> +<input type=submit name=dotest value='Run SSLStrength'> +</tr> +</table> +<input type=hidden name=dotest> +<br> +<br> +</form> +\n"; + +} + + +exit(0); + + +__END__ + + id CipherName Domestic Export + a SSL_EN_RC4_128_WITH_MD5 (ssl2) Yes No + b SSL_EN_RC2_128_CBC_WITH_MD5 (ssl2) Yes No + c SSL_EN_DES_192_EDE3_CBC_WITH_MD5 (ssl2) Yes No + d SSL_EN_DES_64_CBC_WITH_MD5 (ssl2) Yes No + e SSL_EN_RC4_128_EXPORT40_WITH_MD5 (ssl2) Yes Yes + f SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5 (ssl2) Yes Yes + i SSL_RSA_WITH_RC4_128_MD5 (ssl3) Yes Step-up only + j SSL_RSA_WITH_3DES_EDE_CBC_SHA (ssl3) Yes Step-up only + k SSL_RSA_WITH_DES_CBC_SHA (ssl3) Yes No + l SSL_RSA_EXPORT_WITH_RC4_40_MD5 (ssl3) Yes Yes + m SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 (ssl3) Yes Yes + o SSL_RSA_WITH_NULL_MD5 (ssl3) Yes Yes + + + diff --git a/security/nss/cmd/sslstrength/sslstrength.c b/security/nss/cmd/sslstrength/sslstrength.c new file mode 100644 index 000000000..7e8604ed0 --- /dev/null +++ b/security/nss/cmd/sslstrength/sslstrength.c @@ -0,0 +1,622 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 SSLTELNET +#include <termios.h> +#endif + +/* Portable layer header files */ +#include "prinit.h" +#include "prprf.h" +#include "prsystem.h" +#include "prmem.h" +#include "plstr.h" +#include "prnetdb.h" +#include "prinrval.h" + +#include "secutil.h" + +/* Security library files */ +#include "cert.h" +#include "ssl.h" +#include "sslproto.h" +#include "secmod.h" +#include "nss.h" + +/* define this if you want telnet capability! */ + +/* #define SSLTELNET 1 */ + +PRInt32 debug; + +#ifdef DEBUG_stevep +#define dbmsg(x) if (verbose) PR_fprintf(PR_STDOUT,x); +#else +#define dbmsg(x) ; +#endif + + +/* Set SSL Policy to Domestic (strong=1) or Export (strong=0) */ + +#define ALLOW(x) SSL_CipherPolicySet(x,SSL_ALLOWED); SSL_CipherPrefSetDefault(x,1); +#define DISALLOW(x) SSL_CipherPolicySet(x,SSL_NOT_ALLOWED); SSL_CipherPrefSetDefault(x,0); +#define MAYBEALLOW(x) SSL_CipherPolicySet(x,SSL_RESTRICTED); SSL_CipherPrefSetDefault(x,1); + +struct CipherPolicy { + char number; + long id; + char *name; + PRInt32 pref; + PRInt32 domestic; + PRInt32 export; +}; + +struct CipherPolicy ciphers[] = { + { 'a',SSL_EN_RC4_128_WITH_MD5, "SSL_EN_RC4_128_WITH_MD5 (ssl2)",1, SSL_ALLOWED,SSL_NOT_ALLOWED }, + { 'b',SSL_EN_RC2_128_CBC_WITH_MD5, "SSL_EN_RC2_128_CBC_WITH_MD5 (ssl2)",1, SSL_ALLOWED,SSL_NOT_ALLOWED }, + { 'c',SSL_EN_DES_192_EDE3_CBC_WITH_MD5, "SSL_EN_DES_192_EDE3_CBC_WITH_MD5 (ssl2)",1, SSL_ALLOWED,SSL_NOT_ALLOWED }, + { 'd',SSL_EN_DES_64_CBC_WITH_MD5, "SSL_EN_DES_64_CBC_WITH_MD5 (ssl2)",1, SSL_ALLOWED,SSL_NOT_ALLOWED }, + { 'e',SSL_EN_RC4_128_EXPORT40_WITH_MD5, "SSL_EN_RC4_128_EXPORT40_WITH_MD5 (ssl2)",1, SSL_ALLOWED,SSL_ALLOWED }, + { 'f',SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, "SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5 (ssl2)",1, SSL_ALLOWED,SSL_ALLOWED }, +#ifdef FORTEZZA + { 'g',SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA",1,SSL_ALLOWED,SSL_NOT_ALLOWED }, + { 'h',SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, "SSL_FORTEZZA_DMS_WITH_RC4_128_SHA",1, SSL_ALLOWED,SSL_NOT_ALLOWED }, +#endif + { 'i',SSL_RSA_WITH_RC4_128_MD5, "SSL_RSA_WITH_RC4_128_MD5 (ssl3)",1, SSL_ALLOWED,SSL_RESTRICTED }, + { 'j',SSL_RSA_WITH_3DES_EDE_CBC_SHA, "SSL_RSA_WITH_3DES_EDE_CBC_SHA (ssl3)",1, SSL_ALLOWED,SSL_RESTRICTED }, + { 'k',SSL_RSA_WITH_DES_CBC_SHA, "SSL_RSA_WITH_DES_CBC_SHA (ssl3)",1, SSL_ALLOWED,SSL_NOT_ALLOWED }, + { 'l',SSL_RSA_EXPORT_WITH_RC4_40_MD5, "SSL_RSA_EXPORT_WITH_RC4_40_MD5 (ssl3)",1, SSL_ALLOWED,SSL_ALLOWED }, + { 'm',SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, "SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5 (ssl3)",1, SSL_ALLOWED,SSL_ALLOWED }, +#ifdef FORTEZZA + { 'n',SSL_FORTEZZA_DMS_WITH_NULL_SHA, "SSL_FORTEZZA_DMS_WITH_NULL_SHA",1, SSL_ALLOWED,SSL_NOT_ALLOWED }, +#endif + { 'o',SSL_RSA_WITH_NULL_MD5, "SSL_RSA_WITH_NULL_MD5 (ssl3)",1, SSL_ALLOWED,SSL_ALLOWED }, + { 'p',SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, "SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA (ssl3)",1, SSL_ALLOWED,SSL_NOT_ALLOWED }, + { 'q',SSL_RSA_FIPS_WITH_DES_CBC_SHA, "SSL_RSA_FIPS_WITH_DES_CBC_SHA (ssl3)",1, SSL_ALLOWED,SSL_NOT_ALLOWED } + +}; + +void PrintErrString(char *progName,char *msg) { + + PRErrorCode e = PORT_GetError(); + char *s=NULL; + + + if ((e >= PR_NSPR_ERROR_BASE) && (e < PR_MAX_ERROR)) { + + if (e == PR_DIRECTORY_LOOKUP_ERROR) + s = PL_strdup("Hostname Lookup Failed"); + else if (e == PR_NETWORK_UNREACHABLE_ERROR) + s = PL_strdup("Network Unreachable"); + else if (e == PR_CONNECT_TIMEOUT_ERROR) + s = PL_strdup("Connection Timed Out"); + else s = PR_smprintf("%d",e); + + if (!s) return; + } + else { + s = PL_strdup(SECU_ErrorString(e)); + } + + PR_fprintf(PR_STDOUT,"%s: ",progName); + if (s) { + if (*s) + PR_fprintf(PR_STDOUT, "%s\n", s); + else + PR_fprintf(PR_STDOUT, "\n"); + + PR_Free(s); + } + +} + +void PrintCiphers(int onlyenabled) { + int ciphercount,i; + + if (onlyenabled) { + PR_fprintf(PR_STDOUT,"Your Cipher preference:\n"); + } + + ciphercount = sizeof(ciphers)/sizeof(struct CipherPolicy); + PR_fprintf(PR_STDOUT, + " %s %-45s %-12s %-12s\n","id","CipherName","Domestic","Export"); + + for (i=0;i<ciphercount;i++) { + if ( (onlyenabled ==0) || ((onlyenabled==1)&&(ciphers[i].pref))) { + PR_fprintf(PR_STDOUT, + " %c %-45s %-12s %-12s\n",ciphers[i].number,ciphers[i].name, + (ciphers[i].domestic==SSL_ALLOWED)?"Yes": + ( (ciphers[i].domestic==SSL_NOT_ALLOWED)?"No":"Step-up only"), + (ciphers[i].export==SSL_ALLOWED)?"Yes": + ( (ciphers[i].export==SSL_NOT_ALLOWED)?"No":"Step-up only")); + } + } +} + + +void SetPolicy(char *c,int policy) { /* policy==1 : domestic, policy==0, export */ + int i,j,cpolicy; + /* first, enable all relevant ciphers according to policy */ + for (j=0;j<(sizeof(ciphers)/sizeof(struct CipherPolicy));j++) { + SSL_CipherPolicySet(ciphers[j].id,policy?ciphers[j].domestic:ciphers[j].export); + SSL_CipherPrefSetDefault(ciphers[j].id, PR_FALSE); + ciphers[j].pref =0; + } + + + for (i=0;i<(int)PL_strlen(c);i++) { + for (j=0;j<(sizeof(ciphers)/sizeof(struct CipherPolicy));j++) { + if (ciphers[j].number == c[i]) { + cpolicy = policy?ciphers[j].domestic:ciphers[j].export; + if (cpolicy == SSL_NOT_ALLOWED) { + PR_fprintf(PR_STDOUT, "You're trying to enable a cipher (%c:%s) outside of your policy. ignored\n", + c[i],ciphers[j].name); + } + else { + ciphers[j].pref=1; + SSL_CipherPrefSetDefault(ciphers[j].id, PR_TRUE); + } + } + } + } +} + + +int MyAuthCertificateHook(void *arg, PRFileDesc *fd, PRBool checksig, PRBool isserver) { + return SECSuccess; +} + + +void Usage() { +#ifdef SSLTELNET + PR_fprintf(PR_STDOUT,"SSLTelnet "); +#else + PR_fprintf(PR_STDOUT,"SSLStrength (No telnet functionality) "); +#endif + PR_fprintf(PR_STDOUT,"Version 1.5\n"); + + PR_fprintf(PR_STDOUT,"Usage:\n sslstrength hostname[:port] [ciphers=xyz] [certdir=x] [debug] [verbose] " +#ifdef SSLTELNET +"[telnet]|[servertype]|[querystring=<string>] " +#endif +"[policy=export|domestic]\n sslstrength ciphers\n"); +} + + +PRInt32 debug = 0; +PRInt32 verbose = 0; + +PRInt32 main(PRInt32 argc,char **argv, char **envp) +{ + + + /* defaults for command line arguments */ + char *hostnamearg=NULL; + char *portnumarg=NULL; + char *sslversionarg=NULL; + char *keylenarg=NULL; + char *certdir=NULL; + char *hostname; + char *nickname=NULL; + char *progname=NULL; + /* struct sockaddr_in addr; */ + PRNetAddr addr; + + int ss_on; + char *ss_cipher; + int ss_keysize; + int ss_secretsize; + char *ss_issuer; + char *ss_subject; + int policy=1; + char *set_ssl_policy=NULL; + int print_ciphers=0; + + char buf[10]; + char netdbbuf[PR_NETDB_BUF_SIZE]; + PRHostEnt hp; + PRStatus r; + PRNetAddr na; + SECStatus rv; + int portnum=443; /* default https: port */ + PRFileDesc *s,*fd; + + CERTCertDBHandle *handle; + CERTCertificate *c; + PRInt32 i; +#ifdef SSLTELNET + struct termios tmp_tc; + char cb; + int prev_lflag,prev_oflag,prev_iflag; + int t_fin,t_fout; + int servertype=0, telnet=0; + char *querystring=NULL; +#endif + + debug = 0; + + progname = (char *)PL_strrchr(argv[0], '/'); + progname = progname ? progname+1 : argv[0]; + + /* Read in command line args */ + if (argc == 1) { + Usage(); + return(0); + } + + if (! PL_strcmp("ciphers",argv[1])) { + PrintCiphers(0); + exit(0); + } + + hostname = argv[1]; + + if (!PL_strcmp(hostname , "usage") || !PL_strcmp(hostname, "-help") ) { + Usage(); + exit(0); + } + + if ((portnumarg = PL_strchr(hostname,':'))) { + *portnumarg = 0; + portnumarg = &portnumarg[1]; + } + + if (portnumarg) { + if (*portnumarg == 0) { + PR_fprintf(PR_STDOUT,"malformed port number supplied\n"); + return(1); + } + portnum = atoi(portnumarg); + } + + for (i = 2 ; i < argc; i++) + { + if (!PL_strncmp(argv[i] , "sslversion=",11) ) + sslversionarg=&(argv[i][11]); + else if (!PL_strncmp(argv[i], "certdir=",8) ) + certdir = &(argv[i][8]); + else if (!PL_strncmp(argv[i], "ciphers=",8) ) + { + set_ssl_policy=&(argv[i][8]); + } + else if (!PL_strncmp(argv[i], "policy=",7) ) { + if (!PL_strcmp(&(argv[i][7]),"domestic")) policy=1; + else if (!PL_strcmp(&(argv[i][7]),"export")) policy=0; + else { + PR_fprintf(PR_STDOUT,"sslstrength: invalid argument. policy must be one of (domestic,export)\n"); + } + } + else if (!PL_strcmp(argv[i] , "debug") ) + debug = 1; +#ifdef SSLTELNET + else if (!PL_strcmp(argv[i] , "telnet") ) + telnet = 1; + else if (!PL_strcmp(argv[i] , "servertype") ) + servertype = 1; + else if (!PL_strncmp(argv[i] , "querystring=",11) ) + querystring = &argv[i][12]; +#endif + else if (!PL_strcmp(argv[i] , "verbose") ) + verbose = 1; + } + +#ifdef SSLTELNET + if (telnet && (servertype || querystring)) { + PR_fprintf(PR_STDOUT,"You can't use telnet and (server or querystring) options at the same time\n"); + exit(1); + } +#endif + + PR_fprintf(PR_STDOUT,"Using %s policy\n",policy?"domestic":"export"); + + /* allow you to set env var SSLDIR to set the cert directory */ + if (! certdir) certdir = SECU_DefaultSSLDir(); + + /* if we don't have one still, initialize with no databases */ + if (!certdir) { + rv = NSS_NoDB_Init(NULL); + + (void) SECMOD_AddNewModule("Builtins", DLL_PREFIX"nssckbi."DLL_SUFFIX,0,0); + } else { + rv = NSS_Init(certdir); + SECU_ConfigDirectory(certdir); + } + + /* Lookup host */ + r = PR_GetHostByName(hostname,netdbbuf,PR_NETDB_BUF_SIZE,&hp); + + if (r) { + PrintErrString(progname,"Host Name lookup failed"); + return(1); + } + + /* should the third field really be 0? */ + + PR_EnumerateHostEnt(0,&hp,0,&na); + PR_InitializeNetAddr(PR_IpAddrNull,portnum,&na); + + PR_fprintf(PR_STDOUT,"Connecting to %s:%d\n",hostname, portnum); + + /* Create socket */ + + fd = PR_NewTCPSocket(); + if (fd == NULL) { + PrintErrString(progname, "error creating socket"); + return -1; + } + + s = SSL_ImportFD(NULL,fd); + if (s == NULL) { + PrintErrString(progname, "error creating socket"); + return -1; + } + + dbmsg("10: About to enable security\n"); + + rv = SSL_OptionSet(s, SSL_SECURITY, PR_TRUE); + if (rv < 0) { + PrintErrString(progname, "error enabling socket"); + return -1; + } + + if (set_ssl_policy) { + SetPolicy(set_ssl_policy,policy); + } + else { + PR_fprintf(PR_STDOUT,"Using all ciphersuites usually found in client\n"); + if (policy) { + SetPolicy("abcdefghijklmnopqrst",policy); + } + else { + SetPolicy("efghijlmo",policy); + } + } + + PrintCiphers(1); + + rv = SSL_OptionSet(s, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); + if (rv < 0) { + PrintErrString(progname, "error enabling client handshake"); + return -1; + } + + dbmsg("30: About to set AuthCertificateHook\n"); + + + SSL_AuthCertificateHook(s, MyAuthCertificateHook, (void *)handle); + /* SSL_AuthCertificateHook(s, SSL_AuthCertificate, (void *)handle); */ + /* SSL_GetClientAuthDataHook(s, GetClientAuthDataHook, (void *)nickname);*/ + + + dbmsg("40: About to SSLConnect\n"); + + /* Try to connect to the server */ + /* now SSL_Connect takes new arguments. */ + + + r = PR_Connect(s, &na, PR_TicksPerSecond()*5); + if (r < 0) { + PrintErrString(progname, "unable to connect"); + return -1; + } + + rv = SSL_ForceHandshake(s); + + if (rv) { + PrintErrString(progname,"SSL Handshake failed. "); + exit(1); + } + + rv = SSL_SecurityStatus(s, &ss_on, &ss_cipher, + &ss_keysize, &ss_secretsize, + &ss_issuer, &ss_subject); + + + dbmsg("60: done with security status, about to print\n"); + + c = SSL_PeerCertificate(s); + if (!c) PR_fprintf(PR_STDOUT,"Couldn't retrieve peers Certificate\n"); + PR_fprintf(PR_STDOUT,"SSL Connection Status\n",rv); + + PR_fprintf(PR_STDOUT," Cipher: %s\n",ss_cipher); + PR_fprintf(PR_STDOUT," Key Size: %d\n",ss_keysize); + PR_fprintf(PR_STDOUT," Secret Key Size: %d\n",ss_secretsize); + PR_fprintf(PR_STDOUT," Issuer: %s\n",ss_issuer); + PR_fprintf(PR_STDOUT," Subject: %s\n",ss_subject); + + PR_fprintf(PR_STDOUT," Valid: from %s to %s\n", + c==NULL?"???":DER_UTCDayToAscii(&c->validity.notBefore), + c==NULL?"???":DER_UTCDayToAscii(&c->validity.notAfter)); + +#ifdef SSLTELNET + + + + + if (servertype || querystring) { + char buffer[1024]; + char ch; + char qs[] = "HEAD / HTTP/1.0"; + + + + + if (!querystring) querystring = qs; + PR_fprintf(PR_STDOUT,"\nServer query mode\n>>Sending:\n%s\n",querystring); + + PR_fprintf(PR_STDOUT,"\n*** Server said:\n"); + ch = querystring[PL_strlen(querystring)-1]; + if (ch == '"' || ch == '\'') { + PR_fprintf(PR_STDOUT,"Warning: I'm not smart enough to cope with quotes mid-string like that\n"); + } + + rv = PR_Write(s,querystring,PL_strlen(querystring)); + if ((rv < 1) ) { + PR_fprintf(PR_STDOUT,"Oh dear - couldn't send servertype query\n"); + goto closedown; + } + + rv = PR_Write(s,"\r\n\r\n",4); + rv = PR_Read(s,buffer,1024); + if ((rv < 1) ) { + PR_fprintf(PR_STDOUT,"Oh dear - couldn't read server repsonse\n"); + goto closedown; + } + PR_Write(PR_STDOUT,buffer,rv); + } + + + if (telnet) { + + PR_fprintf(PR_STDOUT,"---------------------------\n" + "telnet mode. CTRL-C to exit\n" + "---------------------------\n"); + + + + /* fudge terminal attributes */ + t_fin = PR_FileDesc2NativeHandle(PR_STDIN); + t_fout = PR_FileDesc2NativeHandle(PR_STDOUT); + + tcgetattr(t_fin,&tmp_tc); + prev_lflag = tmp_tc.c_lflag; + prev_oflag = tmp_tc.c_oflag; + prev_iflag = tmp_tc.c_iflag; + tmp_tc.c_lflag &= ~ECHO; + /* tmp_tc.c_oflag &= ~ONLCR; */ + tmp_tc.c_lflag &= ~ICANON; + tmp_tc.c_iflag &= ~ICRNL; + tmp_tc.c_cflag |= CS8; + tmp_tc.c_cc[VMIN] = 1; + tmp_tc.c_cc[VTIME] = 0; + + tcsetattr(t_fin, TCSANOW, &tmp_tc); + /* ioctl(tin, FIONBIO, (char *)&onoff); + ioctl(tout, FIONBIO, (char *)&onoff);*/ + + + { + PRPollDesc pds[2]; + char buffer[1024]; + int amt,amtwritten; + char *x; + + /* STDIN */ + pds[0].fd = PR_STDIN; + pds[0].in_flags = PR_POLL_READ; + pds[1].fd = s; + pds[1].in_flags = PR_POLL_READ | PR_POLL_EXCEPT; + + while (1) { + int nfds; + + nfds = PR_Poll(pds,2,PR_SecondsToInterval(2)); + if (nfds == 0) continue; + + /** read input from keyboard*/ + /* note: this is very inefficient if reading from a file */ + + if (pds[0].out_flags & PR_POLL_READ) { + amt = PR_Read(PR_STDIN,&buffer,1); + /* PR_fprintf(PR_STDOUT,"fd[0]:%d=%d\r\n",amt,buffer[0]); */ + if (amt == 0) { + PR_fprintf(PR_STDOUT,"\n"); + goto loser; + } + + if (buffer[0] == '\r') { + buffer[0] = '\r'; + buffer[1] = '\n'; + amt = 2; + } + rv = PR_Write(PR_STDOUT,buffer,amt); + + + rv = PR_Write(s,buffer,amt); + if (rv == -1) { + PR_fprintf(PR_STDOUT,"Error writing to socket: %d\n",PR_GetError()); + } + } + + /***/ + + + /***/ + if (pds[1].out_flags & PR_POLL_EXCEPT) { + PR_fprintf(PR_STDOUT,"\r\nServer closed connection\r\n"); + goto loser; + } + if (pds[1].out_flags & PR_POLL_READ) { + amt = PR_Read(s,&buffer,1024); + + if (amt == 0) { + PR_fprintf(PR_STDOUT,"\r\nServer closed connection\r\n"); + goto loser; + } + rv = PR_Write(PR_STDOUT,buffer,amt); + } + /***/ + + } + } + loser: + + /* set terminal back to normal */ + tcgetattr(t_fin,&tmp_tc); + + tmp_tc.c_lflag = prev_lflag; + tmp_tc.c_oflag = prev_oflag; + tmp_tc.c_iflag = prev_iflag; + tcsetattr(t_fin, TCSANOW, &tmp_tc); + + /* ioctl(tin, FIONBIO, (char *)&onoff); + ioctl(tout, FIONBIO, (char *)&onoff); */ + } + +#endif + /* SSLTELNET */ + + closedown: + + PR_Close(s); + + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + + return(0); + +} /* main */ + +/*EOF*/ + diff --git a/security/nss/cmd/sslstrength/sslwrap b/security/nss/cmd/sslstrength/sslwrap new file mode 100755 index 000000000..e6955dc92 --- /dev/null +++ b/security/nss/cmd/sslstrength/sslwrap @@ -0,0 +1,181 @@ +#!/usr/bin/perl +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + + +@profiles = ( +# "host:port" "policy" "ciphers" "exp-cipher" "expkeysize" + + [ "cfu:443", "export", "efijlmo", "RC4-40", "40" ], + [ "hbombsgi:448", "export", "efijlmo", "RC4-40", "40" ], + [ "hbombsgi:448", "domestic", "abcdefijklmo", "RC4", "128" ], + [ "gandalf:5666", "domestic", "abcdefijklmo", "RC4", "128" ], + [ "gandalf:5666", "export", "efijlmo", "RC4", "128" ], + [ "gandalf:5666", "domestic", "j", "3DES-EDE-CBC", "168" ], + [ "gandalf:5666", "domestic", "k", "DES-CBC", "56" ], + [ "gandalf:5666", "export", "l", "RC4-40", "40" ], + [ "gandalf:5666", "export", "efijlmo", "RC4", "128" ], + [ "hbombcfu:443", "export", "efijlmo", "RC4", "128" ], + + ); + +$file = &filename; + +open(HTML, ">$file.htm") || die"Cannot open html output file\n"; + +$mutversion = ""; +$platform = $ARGV[0]; + + +print HTML +"<HTML><HEAD> +<TITLE>ssl/sslstrength: Version: $mutversion Platform: $platform Run date mm/dd/yy</TITLE></HEAD><BODY>\n"; + +print HTML +"<TABLE BORDER=1><TR> +<TD><B>Test Case Number</B></TD> +<TD><B>Program</B></TD> +<TD><B>Description of Test Case</B></TD> +<TD><B>Start date/time<B></TD> +<TD><B>End date/time<B></TD> +<TD><B>PASS/FAIL</B></TD> +</TR>\n"; + +$countpass =0; +$countfail =0; + + +$testnum =0; +for $profile (@profiles) { + $testnum ++; + ($host, $policy, $ciphers, $expcipher, $expkeysize) = @$profile; + + $cmd = "./sslstrength $host policy=$policy ciphers=$ciphers"; + + $starttime = &datestring." ".×tring; + print STDERR "$cmd\n"; + open(PIPE, "$cmd|") || die "Cannot start sslstrength\n"; + + $cipher = ""; + $keysize = ""; + while (<PIPE>) { + chop; + if (/^ Cipher: *(.*)/) { + $cipher = $1; + } + if (/^ Secret Key Size: (.*)/) { + $keysize = $1; + } + } + close(PIPE); + $endtime = &datestring." ".×tring; + + if (( $? != 0) || ($cipher ne $expcipher) || ($keysize ne $expkeysize)) { + $countfail ++; + $passed =0; + } + else { + $countpass ++; + $passed =1; + } + +print HTML +"<TR> +<TD><B>$testnum</B></TD> +<TD></TD> +<TD>$cmd</TD> +<TD>$starttime</TD> +<TD>$endtime</TD> +<TD><B>".($passed ? "PASS" : "<FONT COLOR=red>FAIL: return code = +c=$cipher, ec=$expcipher, s=$keysize, es=$expkeysize.</FONT>")." +</B></TD> +</TR>\n"; + +} + +print HTML "</table>\n"; + +close(HTML); + +open (SUM, ">$file.sum") ||die "couldn't open summary file for writing\n"; + +print SUM <<EOM; +[Status] +mut=SSL +mutversion=1.0 +platform=$platform +pass=$countpass +fail=$countfail +knownFail=0 +malformed=0 +EOM + + close(SUM); + + + +sub timestring +{ + + my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time); + my $string; + + $string = sprintf "%2d:%02d:%02d",$hour, $min, $sec; + return $string; +} + +sub datestring +{ + + my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time); + my $string; + + $string = sprintf "%d/%d/%2d",$mon+1, $mday+1, $year; + return $string; +} + +sub filename +{ + + my ($sec, $min, $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time); + my $string; + + $string = sprintf "%04d%02d%02d",$year+1900, $mon+1, $mday; + return $string; +} + + + + + + diff --git a/security/nss/cmd/ssltap/Makefile b/security/nss/cmd/ssltap/Makefile new file mode 100644 index 000000000..f6d8cc93e --- /dev/null +++ b/security/nss/cmd/ssltap/Makefile @@ -0,0 +1,79 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +# Since ssltap doesn't use any of NSS, we'll skip NSS's link libs, +# and just link with NSPR. +# +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + + +-include ../platrules.mk + diff --git a/security/nss/cmd/ssltap/config.mk b/security/nss/cmd/ssltap/config.mk new file mode 100644 index 000000000..23b15fbd5 --- /dev/null +++ b/security/nss/cmd/ssltap/config.mk @@ -0,0 +1,52 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +####################################################################### +# Set the LDFLAGS value to encompass all normal link options, all # +# library names, and all special system linking options # +####################################################################### + +LDFLAGS = \ + $(DYNAMIC_LIB_PATH) \ + $(LDOPTS) \ + $(LIBPLC) \ + $(LIBPR) \ + $(DLLSYSTEM) + +####################################################################### +# Adjust specific variables for all platforms # +####################################################################### + +OS_CFLAGS += -DNSPR20=1 + + diff --git a/security/nss/cmd/ssltap/manifest.mn b/security/nss/cmd/ssltap/manifest.mn new file mode 100644 index 000000000..adfd2bd03 --- /dev/null +++ b/security/nss/cmd/ssltap/manifest.mn @@ -0,0 +1,51 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +EXPORTS = + +CSRCS = ssltap.c \ + $(NULL) + +PROGRAM = ssltap + +REQUIRES = seccmd dbm + +PACKAGE_FILES = ssltap-manual.html licence.doc ssltap.exe + +ARCHIVE_NAME = ssltap + diff --git a/security/nss/cmd/ssltap/ssltap-manual.html b/security/nss/cmd/ssltap/ssltap-manual.html new file mode 100644 index 000000000..28c9e17ee --- /dev/null +++ b/security/nss/cmd/ssltap/ssltap-manual.html @@ -0,0 +1,199 @@ +<HTML>
+<!-- + - The contents of this file are subject to the Mozilla Public + - License Version 1.1 (the "License"); you may not use this file + - except in compliance with the License. You may obtain a copy of + - the License at http://www.mozilla.org/MPL/ + - + - Software distributed under the License is distributed on an "AS + - IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + - implied. See the License for the specific language governing + - rights and limitations under 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. + --> +<HEAD>
+ <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
+ <META NAME="GENERATOR" CONTENT="Mozilla/4.05 [en] (WinNT; U) [Netscape]">
+ <META NAME="Author" CONTENT="Steve Parkinson">
+ <TITLE>SSLTap - manual</TITLE>
+</HEAD>
+<BODY>
+
+<H1>
+SSLTap Manual page</H1>
+
+<H3>
+Summary</H3>
+A command-line proxy which is SSL-aware. It snoops on TCP connections,
+and displays the data going by, including SSL records and handshaking
+if the connection is SSL.
+<H3>
+Synopsis</H3>
+<TT>ssltap [-vhfsxl] [-p port] hostname:port</TT>
+
+<P><TT> -v [prints version string]</TT>
+<BR><TT> -h [outputs hex instead
+of ASCII]</TT>
+<BR><TT> -f [turn on Fancy HTML
+coloring]</TT>
+<BR><TT> -s [turn on SSL decoding]</TT>
+<BR><TT> -x [turn on extra SSL
+hex dumps]</TT>
+<BR><TT> -p port [specify rendezvous port (default 1924)]</TT>
+<BR><TT> -l [loop - continue
+to wait for more connections]</TT>
+<H3>
+Description</H3>
+SSLTap opens a socket on a rendezvous port, and waits for an incoming connection
+(client side). Once this connection arrives, SSLTap makes another connection
+to hostname:port (server side). It passes any data sent by the client to
+the server, and vice versa. However, SSLTap will also display the data
+to the console. It can do this for plain HTTP connections, or any TCP protocol.
+However, SSLTap can also work with SSL streams, as detailed below.
+
+<P>Let's assume your development machine is called 'intercept'. The simplest
+usage of SSLTap is to run the command <TT>'ssltap www.netscape.com:80'</TT>
+on intercept. The program will wait for an incoming connection on port
+1924. Next you would want to go to your browser, and enter the URL http://intercept:1924.
+The page retrieved by the browser will actually be gotten from the server
+at www.netscape.com, but will go via SSLTap.
+
+<P>Data sent from the client to the server is surrounded by a '--> [ ]'
+symbol, and data sent from the server to the client, a '<---[
+]' symbol.
+
+<P>You'll notice that the page retrieved with this example looks incomplete.
+This is because SSLTap by default closes down after the first connection
+is complete, so the browser is not able to load images. To make the SSLTap
+continue to accept connections, switch on looping mode with the -l option.
+
+<P>You can change the default rendezvous port to something else with the
+-p option.
+
+<P>The remaining options change the way the output is produced.
+
+<P>The -f option prints 'fancy' output - in colored HTML. Data sent from
+the client to the server is in blue. The server's reply is in red. This
+is designed so you can load the output up into a browser. When used with
+looping mode, the different connections are separated with horizontal lines.
+
+<P>-x will turn on HEX printing. Instead of being output as ascii, the
+data is shown as Hex, like this:
+<UL><TT><-- [</TT>
+<BR><TT> 0: 56 d5 16 3e a1 6b b1 4a 8f 67 c4 d7
+21 2f 6f dd | V..>.k.J.g..!/o.</TT>
+<BR><TT> 10: bb 22 c4 75 8c f4 ce 28 16 a6 20 aa
+fb 9a 59 a1 | .".u...(.. ...Y.</TT>
+<BR><TT> 20: 51 91 14 d2 fc 9f a7 ea 4d 9c f7 3a
+9d 83 62 4a | Q.......M..:..bJ</TT>
+<BR><TT>]</TT>
+<BR> </UL>
+
+<H4>
+SSL Parse mode</H4>
+The following options deal with SSL connections.
+<UL>-s will turn on SSL parsing. (SSLTap doesn't automatically detect SSL
+sessions.)
+<BR>-x will turn on extra SSL hexdumps. Mostly, if SSL can decode the data,
+it doesn't display the hex.</UL>
+The following SSL3 Data structures are parsed: Handshake, ClientHello,
+ServerHello, CertificateChain, Certificate. In addition, SSL2 ClientHello,
+ServerHello, ClientMasterKey are also partly parsed. NO DECRYPTION IS PERFORMED
+ON THE DATA. SSLTAP CANNOT DECRYPT the data.
+
+<P>If a certificate chain is detected, DER-encoded certificates will be
+saved into files in the current directory called 'cert.0x' where x is the
+sequence number of the certificate.
+<BR>
+<H3>
+Operation Hints</H3>
+Often, you'll find that the server certificate does not get transferred,
+or other parts of the handshake do not happen. This is because the browser
+is taking advantage of session-id-reuse (using the handshake results from
+a previous session). If you restart the browser, it'll clear the session
+id cache.
+
+<P>If you run the ssltap on a different machine that the ssl server you're
+trying to connect to, the browser will complain that the host name you're
+trying to connect to is different to the certificate, but it will still
+let you connect, after showing you a dialog.
+<H3>
+Bugs</H3>
+Please contact <A HREF="mailto:ssltap-support@netscape.com">ssltap-support@netscape.com</A>
+for bug reports.
+<H3>
+History</H3>
+2.1 - First public release (March 1998)
+<BR>
+<H3>
+Other</H3>
+For reference, here is a table of some well-known port numbers:
+<BR>
+<TABLE BORDER=2 >
+<TR>
+<TD>HTTP</TD>
+
+<TD>80</TD>
+</TR>
+
+<TR>
+<TD>SMTP</TD>
+
+<TD>25</TD>
+</TR>
+
+<TR>
+<TD>HTTPS</TD>
+
+<TD>443</TD>
+</TR>
+
+<TR>
+<TD>FTP</TD>
+
+<TD>21</TD>
+</TR>
+
+<TR>
+<TD>IMAPS</TD>
+
+<TD>993</TD>
+</TR>
+
+<TR>
+<TD>NNTP</TD>
+
+<TD>119</TD>
+</TR>
+
+<TR>
+<TD>NNTPS</TD>
+
+<TD>563</TD>
+</TR>
+</TABLE>
+
+
+<P>
+</BODY>
+</HTML>
diff --git a/security/nss/cmd/ssltap/ssltap.c b/security/nss/cmd/ssltap/ssltap.c new file mode 100644 index 000000000..daca2949f --- /dev/null +++ b/security/nss/cmd/ssltap/ssltap.c @@ -0,0 +1,1334 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* + * ssltap.c + * + * Version 1.0 : Frederick Roeber : 11 June 1997 + * Version 2.0 : Steve Parkinson : 13 November 1997 + * Version 3.0 : Nelson Bolyard : 22 July 1998 + * Version 3.1 : Nelson Bolyard : 24 May 1999 + * + * changes in version 2.0: + * Uses NSPR20 + * Shows structure of SSL negotiation, if enabled. + * + * This "proxies" a socket connection (like a socks tunnel), but displays the + * data is it flies by. + * + * In the code, the 'client' socket is the one on the client side of the + * proxy, and the server socket is on the server side. + * + */ + +#include "nspr.h" +#include "plstr.h" +#include "secutil.h" +#include <memory.h> /* for memcpy, etc. */ +#include <string.h> +#include <time.h> + +#include "plgetopt.h" + +#define VERSIONSTRING "$Revision$ ($Date$) $Author$" + + +struct _DataBufferList; +struct _DataBuffer; + +typedef struct _DataBufferList { + struct _DataBuffer *first,*last; + int size; + int isEncrypted; +} DataBufferList; + +typedef struct _DataBuffer { + unsigned char *buffer; + int length; + int offset; /* offset of first good byte */ + struct _DataBuffer *next; +} DataBuffer; + + +DataBufferList + clientstream = {NULL, NULL, 0, 0}, + serverstream = {NULL, NULL, 0, 0}; + +struct sslhandshake { + PRUint8 type; + PRUint32 length; +}; + +typedef struct _SSLRecord { + PRUint8 type; + PRUint8 ver_maj,ver_min; + + PRUint8 length[2]; +} SSLRecord; + +typedef struct _ClientHelloV2 { + PRUint8 length[2]; + PRUint8 type; + PRUint8 version[2]; + PRUint8 cslength[2]; + PRUint8 sidlength[2]; + PRUint8 rndlength[2]; + PRUint8 csuites[1]; +} ClientHelloV2; + +typedef struct _ServerHelloV2 { + PRUint8 length[2]; + PRUint8 type; + PRUint8 sidhit; + PRUint8 certtype; + PRUint8 version[2]; + PRUint8 certlength[2]; + PRUint8 cslength[2]; + PRUint8 cidlength[2]; +} ServerHelloV2; + +typedef struct _ClientMasterKeyV2 { + PRUint8 length[2]; + PRUint8 type; + + PRUint8 cipherkind[3]; + PRUint8 clearkey[2]; + PRUint8 secretkey[2]; + +} ClientMasterKeyV2; + + + +#define TAPBUFSIZ 16384 + +#define DEFPORT 1924 +#include <ctype.h> + +int hexparse=0; +int sslparse=0; +int sslhexparse=0; +int looparound=0; +int fancy=0; +int isV2Session=0; + +#define GET_SHORT(x) ((PRUint16)(((PRUint16)((PRUint8*)x)[0]) << 8) + ((PRUint16)((PRUint8*)x)[1])) +#define GET_24(x) ((PRUint32) ( \ + (((PRUint32)((PRUint8*)x)[0]) << 16) \ + + \ + (((PRUint32)((PRUint8*)x)[1]) << 8) \ + + \ + (((PRUint32)((PRUint8*)x)[2]) << 0) \ + ) ) + +void print_hex(int amt, unsigned char *buf); +void read_stream_bytes(unsigned char *d, DataBufferList *db, int length); + +void myhalt(int dblsize,int collectedsize) { + + while(1) ; + +} + +const char *get_error_text(int error) { + switch (error) { + case PR_IO_TIMEOUT_ERROR: + return "Timeout"; + break; + case PR_CONNECT_REFUSED_ERROR: + return "Connection refused"; + break; + case PR_NETWORK_UNREACHABLE_ERROR: + return "Network unreachable"; + break; + case PR_BAD_ADDRESS_ERROR: + return "Bad address"; + break; + case PR_CONNECT_RESET_ERROR: + return "Connection reset"; + break; + case PR_PIPE_ERROR: + return "Pipe error"; + break; + } + + return ""; +} + + + + + +void check_integrity(DataBufferList *dbl) { + DataBuffer *db; + int i; + + db = dbl->first; + i =0; + while (db) { + i+= db->length - db->offset; + db = db->next; + } + if (i != dbl->size) { + myhalt(dbl->size,i); + } +} + +/* Free's the DataBuffer at the head of the list and returns the pointer + * to the new head of the list. + */ +DataBuffer * +free_head(DataBufferList *dbl) +{ + DataBuffer *db = dbl->first; + PR_ASSERT(db->offset >= db->length); + if (db->offset >= db->length) { + dbl->first = db->next; + if (dbl->first == NULL) { + dbl->last = NULL; + } + PR_Free(db->buffer); + PR_Free(db); + db = dbl->first; + } + return db; +} + +void +read_stream_bytes(unsigned char *d, DataBufferList *dbl, int length) { + int copied = 0; + DataBuffer *db = dbl->first; + + if (!db) { + PR_fprintf(PR_STDERR,"assert failed - dbl->first is null\n"); + exit(8); + } + while (length) { + int toCopy; + /* find the number of bytes to copy from the head buffer */ + /* if there's too many in this buffer, then only copy 'length' */ + toCopy = PR_MIN(db->length - db->offset, length); + + memcpy(d + copied, db->buffer + db->offset, toCopy); + copied += toCopy; + db->offset += toCopy; + length -= toCopy; + dbl->size -= toCopy; + + /* if we emptied the head buffer */ + if (db->offset >= db->length) { + db = free_head(dbl); + } + } + + check_integrity(dbl); + +} + +void +flush_stream(DataBufferList *dbl) +{ + DataBuffer *db = dbl->first; + check_integrity(dbl); + while (db) { + db->offset = db->length; + db = free_head(dbl); + } + dbl->size = 0; + check_integrity(dbl); +} + + +const char * V2CipherString(int cs_int) { + char *cs_str; + cs_str = NULL; + switch (cs_int) { + + case 0x010080: cs_str = "SSL2/RSA/RC4-128/MD5"; break; + case 0x020080: cs_str = "SSL2/RSA/RC4-40/MD5"; break; + case 0x030080: cs_str = "SSL2/RSA/RC2CBC128/MD5"; break; + case 0x040080: cs_str = "SSL2/RSA/RC2CBC40/MD5"; break; + case 0x050080: cs_str = "SSL2/RSA/IDEA128CBC/MD5"; break; + case 0x060040: cs_str = "SSL2/RSA/DES56-CBC/MD5"; break; + case 0x0700C0: cs_str = "SSL2/RSA/3DES192EDE-CBC/MD5"; break; + + case 0x000001: cs_str = "SSL3/RSA/NULL/MD5"; break; + case 0x000002: cs_str = "SSL3/RSA/NULL/SHA"; break; + case 0x000003: cs_str = "SSL3/RSA/RC4-40/MD5"; break; + case 0x000004: cs_str = "SSL3/RSA/RC4-128/MD5"; break; + case 0x000005: cs_str = "SSL3/RSA/RC4-128/SHA"; break; + case 0x000006: cs_str = "SSL3/RSA/RC2CBC40/MD5"; break; + case 0x000007: cs_str = "SSL3/RSA/IDEA128CBC/SHA"; break; + case 0x000008: cs_str = "SSL3/RSA/DES40-CBC/SHA"; break; + case 0x000009: cs_str = "SSL3/RSA/DES56-CBC/SHA"; break; + case 0x00000A: cs_str = "SSL3/RSA/3DES192EDE-CBC/SHA"; break; + + case 0x00000B: cs_str = "SSL3/DH-DSS/DES40-CBC/SHA"; break; + case 0x00000C: cs_str = "SSL3/DH_DSS/DES56-CBC/SHA"; break; + case 0x00000D: cs_str = "SSL3/DH-DSS/DES192EDE3CBC/SHA"; break; + case 0x00000E: cs_str = "SSL3/DH-RSA/DES40-CBC/SHA"; break; + case 0x00000F: cs_str = "SSL3/DH_RSA/DES56-CBC/SHA"; break; + case 0x000010: cs_str = "SSL3/DH-RSA/3DES192EDE-CBC/SHA"; break; + + case 0x000011: cs_str = "SSL3/DHE-DSS/DES40-CBC/SHA"; break; + case 0x000012: cs_str = "SSL3/DHE_DSS/DES56-CBC/SHA"; break; + case 0x000013: cs_str = "SSL3/DHE-DSS/DES192EDE3CBC/SHA"; break; + case 0x000014: cs_str = "SSL3/DHE-RSA/DES40-CBC/SHA"; break; + case 0x000015: cs_str = "SSL3/DHE_RSA/DES56-CBC/SHA"; break; + case 0x000016: cs_str = "SSL3/DHE-RSA/3DES192EDE-CBC/SHA"; break; + + case 0x000017: cs_str = "SSL3/DH-anon/RC4-40/MD5"; break; + case 0x000018: cs_str = "SSL3/DH-anon/RC4-128/MD5"; break; + case 0x000019: cs_str = "SSL3/DH-anon/DES40-CBC/SHA"; break; + case 0x00001A: cs_str = "SSL3/DH-anon/DES56-CBC/SHA"; break; + case 0x00001B: cs_str = "SSL3/DH-anon/3DES192EDE-CBC/SHA"; break; + + case 0x00001C: cs_str = "SSL3/FORTEZZA-DMS/NULL/SHA"; break; + case 0x00001D: cs_str = "SSL3/FORTEZZA-DMS/FORTEZZA-CBC/SHA"; break; + case 0x00001E: cs_str = "SSL3/FORTEZZA-DMS/RC4-128/SHA"; break; + + case 0x000062: cs_str = "TLS/RSA_EXPORT1024/DES56_CBC/SHA"; break; + case 0x000064: cs_str = "TLS/RSA_EXPORT1024/RC4-56/SHA"; break; + case 0x000063: cs_str = "TLS/DHE-DSS_EXPORT1024/DES56-CBC/SHA"; break; + case 0x000065: cs_str = "TLS/DHE-DSS_EXPORT1024/RC4-56/SHA"; break; + case 0x000066: cs_str = "TLS/DHE-DSS/RC4-128/SHA"; break; + + case 0x00ffe1: cs_str = "SSL3/RSA-FIPS/DES56-CBC/SHA"; break; + case 0x00ffe0: cs_str = "SSL3/RSA-FIPS/3DES192EDE-CBC/SHA"; break; + + /* the string literal is broken up to avoid trigraphs */ + default: cs_str = "????" "/????????" "/?????????" "/???"; break; + } + + return cs_str; +} + +void partial_packet(int thispacket, int size, int needed) +{ + PR_fprintf(PR_STDOUT,"(%u bytes", thispacket); + if (thispacket < needed) { + PR_fprintf(PR_STDOUT,", making %u", size); + } + PR_fprintf(PR_STDOUT," of %u", needed); + if (size > needed) { + PR_fprintf(PR_STDOUT,", with %u left over", size - needed); + } + PR_fprintf(PR_STDOUT,")\n"); +} + +char * get_time_string(void) +{ + char *cp; + char *eol; + time_t tt; + + time(&tt); + cp = ctime(&tt); + eol = strchr(cp, '\n'); + if (eol) + *eol = 0; + return cp; +} + +void print_sslv2(DataBufferList *s, unsigned char *tbuf, unsigned int alloclen) +{ + ClientHelloV2 *chv2; + ServerHelloV2 *shv2; + unsigned char *pos; + unsigned int p; + unsigned int q; + PRUint32 len; + + chv2 = (ClientHelloV2 *)tbuf; + shv2 = (ServerHelloV2 *)tbuf; + if (s->isEncrypted) { + PR_fprintf(PR_STDOUT," [ssl2] Encrypted {...}\n"); + return; + } + PR_fprintf(PR_STDOUT," [%s]", get_time_string() ); + switch(chv2->type) { + case 1: + PR_fprintf(PR_STDOUT," [ssl2] ClientHelloV2 {\n"); + PR_fprintf(PR_STDOUT," version = {0x%02x, 0x%02x}\n", + (PRUint32)chv2->version[0],(PRUint32)chv2->version[1]); + PR_fprintf(PR_STDOUT," cipher-specs-length = %d (0x%02x)\n", + (PRUint32)(GET_SHORT((chv2->cslength))), + (PRUint32)(GET_SHORT((chv2->cslength)))); + PR_fprintf(PR_STDOUT," sid-length = %d (0x%02x)\n", + (PRUint32)(GET_SHORT((chv2->sidlength))), + (PRUint32)(GET_SHORT((chv2->sidlength)))); + PR_fprintf(PR_STDOUT," challenge-length = %d (0x%02x)\n", + (PRUint32)(GET_SHORT((chv2->rndlength))), + (PRUint32)(GET_SHORT((chv2->rndlength)))); + PR_fprintf(PR_STDOUT," cipher-suites = { \n"); + for (p=0;p<GET_SHORT((chv2->cslength));p+=3) { + const char *cs_str=NULL; + PRUint32 cs_int=0; + cs_int = GET_24((&chv2->csuites[p])); + cs_str = V2CipherString(cs_int); + + PR_fprintf(PR_STDOUT," (0x%06x) %s\n", + cs_int, cs_str); + } + q = p; + PR_fprintf(PR_STDOUT," }\n"); + if (chv2->sidlength) { + PR_fprintf(PR_STDOUT," session-id = { "); + for (p=0;p<GET_SHORT((chv2->sidlength));p+=2) { + PR_fprintf(PR_STDOUT,"0x%04x ",(PRUint32)(GET_SHORT((&chv2->csuites[p+q])))); + } + } + q += p; + PR_fprintf(PR_STDOUT,"}\n"); + if (chv2->rndlength) { + PR_fprintf(PR_STDOUT," challenge = { "); + for (p=0;p<GET_SHORT((chv2->rndlength));p+=2) { + PR_fprintf(PR_STDOUT,"0x%04x ",(PRUint32)(GET_SHORT((&chv2->csuites[p+q])))); + } + PR_fprintf(PR_STDOUT,"}\n"); + } + PR_fprintf(PR_STDOUT,"}\n"); + break; + /* end of V2 CLientHello Parsing */ + + case 2: /* Client Master Key */ + { + const char *cs_str=NULL; + PRUint32 cs_int=0; + ClientMasterKeyV2 *cmkv2; + cmkv2 = (ClientMasterKeyV2 *)chv2; + isV2Session = 1; + + PR_fprintf(PR_STDOUT," [ssl2] ClientMasterKeyV2 { \n"); + + cs_int = GET_24(&cmkv2->cipherkind[0]); + cs_str = V2CipherString(cs_int); + PR_fprintf(PR_STDOUT," cipher-spec-chosen = (0x%06x) %s\n", + cs_int, cs_str); + + PR_fprintf(PR_STDOUT," clear-portion = %d bits\n", + 8*(PRUint32)(GET_SHORT((cmkv2->clearkey)))); + + PR_fprintf(PR_STDOUT," }\n"); + clientstream.isEncrypted = 1; + serverstream.isEncrypted = 1; + } + break; + + + case 3: + PR_fprintf(PR_STDOUT," [ssl2] Client Finished V2 {...}\n"); + isV2Session = 1; + break; + + + case 4: /* V2 Server Hello */ + isV2Session = 1; + + PR_fprintf(PR_STDOUT," [ssl2] ServerHelloV2 {\n"); + PR_fprintf(PR_STDOUT," sid hit = {0x%02x}\n", + (PRUintn)shv2->sidhit); + PR_fprintf(PR_STDOUT," version = {0x%02x, 0x%02x}\n", + (PRUint32)shv2->version[0],(PRUint32)shv2->version[1]); + PR_fprintf(PR_STDOUT," cipher-specs-length = %d (0x%02x)\n", + (PRUint32)(GET_SHORT((shv2->cslength))), + (PRUint32)(GET_SHORT((shv2->cslength)))); + PR_fprintf(PR_STDOUT," sid-length = %d (0x%02x)\n", + (PRUint32)(GET_SHORT((shv2->cidlength))), + (PRUint32)(GET_SHORT((shv2->cidlength)))); + + pos = (unsigned char *)shv2; + pos += 2; /* skip length header */ + pos += 11; /* position pointer to Certificate data area */ + q = GET_SHORT(&shv2->certlength); + if (q >alloclen) { + goto eosh; + } + pos += q; /* skip certificate */ + + PR_fprintf(PR_STDOUT," cipher-suites = { "); + len = GET_SHORT((shv2->cslength)); + for (p = 0; p < len; p += 3) { + const char *cs_str=NULL; + PRUint32 cs_int=0; + cs_int = GET_24((pos+p)); + cs_str = V2CipherString(cs_int); + PR_fprintf(PR_STDOUT,"\n "); + PR_fprintf(PR_STDOUT,"(0x%06x) %s", cs_int, cs_str); + } + pos += len; + PR_fprintf(PR_STDOUT," }\n"); /* End of cipher suites */ + len = (PRUint32)GET_SHORT((shv2->cidlength)); + if (len) { + PR_fprintf(PR_STDOUT," connection-id = { "); + for (p = 0; p < len; p += 2) { + PR_fprintf(PR_STDOUT,"0x%04x ", (PRUint32)(GET_SHORT((pos + p)))); + } + PR_fprintf(PR_STDOUT," }\n"); /* End of connection id */ + } +eosh: + PR_fprintf(PR_STDOUT,"\n }\n"); /* end of ServerHelloV2 */ + if (shv2->sidhit) { + clientstream.isEncrypted = 1; + serverstream.isEncrypted = 1; + } + break; + + case 5: + PR_fprintf(PR_STDOUT," [ssl2] Server Verify V2 {...}\n"); + isV2Session = 1; + break; + + case 6: + PR_fprintf(PR_STDOUT," [ssl2] Server Finished V2 {...}\n"); + isV2Session = 1; + break; + + case 7: + PR_fprintf(PR_STDOUT," [ssl2] Request Certificate V2 {...}\n"); + isV2Session = 1; + break; + + case 8: + PR_fprintf(PR_STDOUT," [ssl2] Client Certificate V2 {...}\n"); + isV2Session = 1; + break; + + default: + PR_fprintf(PR_STDOUT," [ssl2] UnknownType 0x%02x {...}\n", + (PRUint32)chv2->type); + break; + } +} + + + + + + +void print_ssl3_handshake(unsigned char *tbuf, + unsigned int alloclen, + SSLRecord * sr) +{ + struct sslhandshake sslh; + unsigned char * hsdata; + int offset=0; + + PR_fprintf(PR_STDOUT," handshake {\n"); + + while (offset < alloclen) { + sslh.type = tbuf[offset]; + sslh.length = GET_24(tbuf+offset+1); + hsdata= &tbuf[offset+4]; + + if (sslhexparse) print_hex(4,tbuf+offset); + + PR_fprintf(PR_STDOUT," type = %d (",sslh.type); + switch(sslh.type) { + case 0: PR_fprintf(PR_STDOUT,"hello_request)\n"); break; + case 1: PR_fprintf(PR_STDOUT,"client_hello)\n"); break; + case 2: PR_fprintf(PR_STDOUT,"server_hello)\n"); break; + case 11: PR_fprintf(PR_STDOUT,"certificate)\n"); break; + case 12: PR_fprintf(PR_STDOUT,"server_key_exchange)\n"); break; + case 13: PR_fprintf(PR_STDOUT,"certificate_request)\n"); break; + case 14: PR_fprintf(PR_STDOUT,"server_hello_done)\n"); break; + case 15: PR_fprintf(PR_STDOUT,"certificate_verify)\n"); break; + case 16: PR_fprintf(PR_STDOUT,"client_key_exchange)\n"); break; + case 20: PR_fprintf(PR_STDOUT,"finished)\n"); break; + default: PR_fprintf(PR_STDOUT,"unknown)\n"); + } + + PR_fprintf(PR_STDOUT," length = %d (0x%06x)\n",sslh.length,sslh.length); + switch (sslh.type) { + + case 1: /* client hello */ + switch (sr->ver_maj) { + case 2: /* ssl version 2 */ + PR_fprintf(PR_STDOUT," ClientHelloV2 {...}\n"); + break; + case 3: /* ssl version 3 */ + { + int sidlength,pos,csuitelength,w; + PR_fprintf(PR_STDOUT," ClientHelloV3 {\n"); + PR_fprintf(PR_STDOUT," client_version = {%d, %d}\n", + (PRUint8)hsdata[0],(PRUint8)hsdata[1]); + PR_fprintf(PR_STDOUT," random = {...}\n"); + if (sslhexparse) print_hex(32,&hsdata[2]); + PR_fprintf(PR_STDOUT," session ID = {\n"); + sidlength = (int)hsdata[2+32]; + PR_fprintf(PR_STDOUT," length = %d\n",sidlength); + PR_fprintf(PR_STDOUT," contents = {..}\n"); + if (sslhexparse) print_hex(sidlength,&hsdata[2+32+1]); + PR_fprintf(PR_STDOUT," }\n"); + pos = 2+32+1+sidlength; + csuitelength = GET_SHORT((hsdata+pos)); + PR_fprintf(PR_STDOUT," cipher_suites[%d] = { \n", + csuitelength/2); + if (csuitelength%1) { + PR_fprintf(PR_STDOUT, + "*error in protocol - csuitelength shouldn't be odd*\n"); + } + + for (w=0; w<csuitelength; w+=2) { + const char *cs_str=NULL; + PRUint32 cs_int=0; + cs_int = GET_SHORT((hsdata+pos+2+w)); + cs_str = V2CipherString(cs_int); + + PR_fprintf(PR_STDOUT, + " (0x%04x) %s\n", cs_int, cs_str); + } + + /* for (w=0;w<csuitelength;w+=2) { + PR_fprintf(PR_STDOUT,"0x%04x ",GET_SHORT((hsdata+pos+2+w))); + } */ + + PR_fprintf(PR_STDOUT,"\n }\n"); + PR_fprintf(PR_STDOUT," }\n"); + + + + } /* end of ssl version 3 */ + break; + default: + PR_fprintf(PR_STDOUT," ClientHelloUndefinedVersion{}\n"); + } /* end of switch sr->ver_maj */ + break; + + case 2: /* server hello */ + { + int sidlength, pos; + const char *cs_str=NULL; + PRUint32 cs_int=0; + PR_fprintf(PR_STDOUT," ServerHello {\n"); + PR_fprintf(PR_STDOUT," server_version = {%d, %d}\n", + (PRUint8)hsdata[0],(PRUint8)hsdata[1]); + PR_fprintf(PR_STDOUT," random = {...}\n"); + if (sslhexparse) print_hex(32,&hsdata[2]); + PR_fprintf(PR_STDOUT," session ID = {\n"); + sidlength = (int)hsdata[2+32]; + PR_fprintf(PR_STDOUT," length = %d\n",sidlength); + PR_fprintf(PR_STDOUT," contents = {..}\n"); + if (sslhexparse) print_hex(sidlength,&hsdata[2+32+1]); + PR_fprintf(PR_STDOUT," }\n"); + pos = 2+32+1+sidlength; + cs_int = GET_SHORT((hsdata+pos)); + cs_str = V2CipherString(cs_int); + PR_fprintf(PR_STDOUT," cipher_suite = (0x%04x) %s\n", + cs_int, cs_str); + PR_fprintf(PR_STDOUT," }\n"); + } + break; + + + + case 11: /* certificate */ + { + PRFileDesc *cfd; + int pos; + int certslength; + int certlength; + int certbytesread = 0; + static int certFileNumber; + char certFileName[20]; + + PR_fprintf(PR_STDOUT," CertificateChain {\n"); + certslength = GET_24(hsdata); + PR_fprintf(PR_STDOUT," chainlength = %d (0x%04x)\n", + certslength,certslength); + pos = 3; + while (certbytesread < certslength) { + certlength = GET_24((hsdata+pos)); + pos += 3; + PR_fprintf(PR_STDOUT," Certificate {\n"); + PR_fprintf(PR_STDOUT," size = %d (0x%04x)\n", + certlength,certlength); + + PR_snprintf(certFileName, sizeof certFileName, "cert.%03d", + ++certFileNumber); + cfd = PR_Open(certFileName, PR_WRONLY|PR_CREATE_FILE, 0664); + if (!cfd) { + PR_fprintf(PR_STDOUT, + " data = { couldn't save file '%s' }\n", + certFileName); + } else { + PR_Write(cfd, (hsdata+pos), certlength); + PR_fprintf(PR_STDOUT, + " data = { saved in file '%s' }\n", + certFileName); + PR_Close(cfd); + } + + PR_fprintf(PR_STDOUT," }\n"); + pos += certlength; + certbytesread += certlength+3; + } + PR_fprintf(PR_STDOUT," }\n"); + } + break; + + case 13: /* certificate request */ + if (sslhexparse) { + PR_fprintf(PR_STDOUT," CertificateRequest {\n"); + print_hex(sslh.length, hsdata); + PR_fprintf(PR_STDOUT," }\n"); + } + break; + + case 16: /* client key exchange */ + { + PR_fprintf(PR_STDOUT," ClientKeyExchange {\n"); + PR_fprintf(PR_STDOUT," message = {...}\n"); + PR_fprintf(PR_STDOUT," }\n"); + } + break; + + } /* end of switch sslh.type */ + offset += sslh.length + 4; /* +4 because of length (3 bytes) and type (1 byte) */ + } /* while */ + PR_fprintf(PR_STDOUT," }\n"); +} + + +void print_ssl(DataBufferList *s, int length, unsigned char *buffer) +{ + /* -------------------------------------------------------- */ + /* first, create a new buffer object for this piece of data. */ + + DataBuffer *db; + int i,l; + + if (s->size == 0 && length > 0 && buffer[0] >= 32 && buffer[0] < 128) { + /* Not an SSL record, treat entire buffer as plaintext */ + PR_Write(PR_STDOUT,buffer,length); + return; + } + + + check_integrity(s); + + i = 0; + l = length; + + db = PR_NEW(struct _DataBuffer); + + db->buffer = (unsigned char*)PR_Malloc(length); + db->length = length; + db->offset = 0; + memcpy(db->buffer, buffer, length); + db->next = NULL; + + /* now, add it to the stream */ + + if (s->last != NULL) s->last->next = db; + s->last = db; + s->size += length; + if (s->first == NULL) s->first = db; + + check_integrity(s); + + /*------------------------------------------------------- */ + /* now we look at the stream to see if we have enough data to + decode */ + + while (s->size > 0 ) { + unsigned char *tbuf = NULL; + + SSLRecord sr; + unsigned alloclen; + unsigned recordsize; + + check_integrity(s); + + if ( s->first == NULL) { + PR_fprintf(PR_STDOUT,"ERROR: s->first is null\n"); + exit(9); + } + + /* in the case of an SSL 2 client-hello (which is all ssltap supports) */ + /* will have the high-bit set, whereas an SSL 3 client-hello will not */ + /* SSL2 can also send records that begin with the high bit clear. + * This code will incorrectly handle them. XXX + */ + if (isV2Session || s->first->buffer[s->first->offset] & 0x80) { + /* it's an SSL 2 packet */ + unsigned char lenbuf[3]; + + /* first, we check if there's enough data for it to be an SSL2-type + * record. What a pain.*/ + if (s->size < sizeof lenbuf) { + partial_packet(length, s->size, sizeof lenbuf); + return; + } + + /* read the first two bytes off the stream. */ + read_stream_bytes(lenbuf, s, sizeof(lenbuf)); + alloclen = ((unsigned int)(lenbuf[0] & 0x7f) << 8) + lenbuf[1] + + ((lenbuf[0] & 0x80) ? 2 : 3); + PR_fprintf(PR_STDOUT, "alloclen = %u bytes\n", alloclen); + + /* put 'em back on the head of the stream. */ + db = PR_NEW(struct _DataBuffer); + + db->length = sizeof lenbuf; + db->buffer = (unsigned char*) PR_Malloc(db->length); + db->offset = 0; + memcpy(db->buffer, lenbuf, sizeof lenbuf); + + db->next = s->first; + s->first = db; + if (s->last == NULL) + s->last = db; + s->size += db->length; + + /* if there wasn't enough, go back for more. */ + if (s->size < alloclen) { + check_integrity(s); + partial_packet(length, s->size, alloclen); + return; + } + partial_packet(length, s->size, alloclen); + + /* read in the whole record. */ + tbuf = PR_Malloc(alloclen); + read_stream_bytes(tbuf, s, alloclen); + + print_sslv2(s, tbuf, alloclen); + PR_FREEIF(tbuf); + check_integrity(s); + + continue; + } + + /***********************************************************/ + /* It's SSL v3 */ + /***********************************************************/ + check_integrity(s); + + if (s->size < sizeof(SSLRecord)) { + partial_packet(length, s->size, sizeof(SSLRecord)); + return; + } + + read_stream_bytes((unsigned char *)&sr, s, sizeof sr); + + /* we have read the stream bytes. Look at the length of + the ssl record. If we don't have enough data to satisfy this + request, then put the bytes we just took back at the head + of the queue */ + recordsize = GET_SHORT(sr.length); + + if (recordsize > s->size) { + db = PR_NEW(struct _DataBuffer); + + db->length = sizeof sr; + db->buffer = (unsigned char*) PR_Malloc(db->length); + db->offset = 0; + memcpy(db->buffer, &sr, sizeof sr); + db->next = s->first; + + /* now, add it back on to the head of the stream */ + + s->first = db; + if (s->last == NULL) + s->last = db; + s->size += db->length; + + check_integrity(s); + partial_packet(length, s->size, recordsize); + return; + } + partial_packet(length, s->size, recordsize); + + + PR_fprintf(PR_STDOUT,"SSLRecord { [%s]\n", get_time_string() ); + if (sslhexparse) { + print_hex(5,(unsigned char*)&sr); + } + + check_integrity(s); + + PR_fprintf(PR_STDOUT," type = %d (",sr.type); + switch(sr.type) { + case 20 : + PR_fprintf(PR_STDOUT,"change_cipher_spec)\n"); + break; + case 21 : + PR_fprintf(PR_STDOUT,"alert)\n"); + break; + case 22 : + PR_fprintf(PR_STDOUT,"handshake)\n"); + break; + case 23 : + PR_fprintf(PR_STDOUT,"application_data)\n"); + break; + default: + PR_fprintf(PR_STDOUT,"unknown)\n"); + break; + } + PR_fprintf(PR_STDOUT," version = { %d,%d }\n", + (PRUint32)sr.ver_maj,(PRUint32)sr.ver_min); + PR_fprintf(PR_STDOUT," length = %d (0x%x)\n", + (PRUint32)GET_SHORT(sr.length), (PRUint32)GET_SHORT(sr.length)); + + + alloclen = recordsize; + PR_ASSERT(s->size >= alloclen); + if (s->size >= alloclen) { + tbuf = (unsigned char*) PR_Malloc(alloclen); + read_stream_bytes(tbuf, s, alloclen); + + if (s->isEncrypted) { + PR_fprintf(PR_STDOUT," < encrypted >\n"); + } else + + switch(sr.type) { + case 20 : /* change_cipher_spec */ + if (sslhexparse) print_hex(alloclen,tbuf); + s->isEncrypted = 1; /* mark to say we can only dump hex form now on */ + break; + + case 21 : /* alert */ + switch(tbuf[0]) { + case 1: PR_fprintf(PR_STDOUT, " warning: "); break; + case 2: PR_fprintf(PR_STDOUT, " fatal: "); break; + default: PR_fprintf(PR_STDOUT, " unknown level %d: ", tbuf[0]); break; + } + + switch(tbuf[1]) { + case 0: PR_fprintf(PR_STDOUT, "close notify\n"); break; + case 10: PR_fprintf(PR_STDOUT, "unexpected message\n"); break; + case 20: PR_fprintf(PR_STDOUT, "bad record mac\n"); break; + case 21: PR_fprintf(PR_STDOUT, "decryption failed\n"); break; + case 22: PR_fprintf(PR_STDOUT, "record overflow\n"); break; + case 30: PR_fprintf(PR_STDOUT, "decompression failure\n"); break; + case 40: PR_fprintf(PR_STDOUT, "handshake failure\n"); break; + case 41: PR_fprintf(PR_STDOUT, "no certificate\n"); break; + case 42: PR_fprintf(PR_STDOUT, "bad certificate\n"); break; + case 43: PR_fprintf(PR_STDOUT, "unsupported certificate\n"); break; + case 44: PR_fprintf(PR_STDOUT, "certificate revoked\n"); break; + case 45: PR_fprintf(PR_STDOUT, "certificate expired\n"); break; + case 46: PR_fprintf(PR_STDOUT, "certificate unknown\n"); break; + case 47: PR_fprintf(PR_STDOUT, "illegal parameter\n"); break; + case 48: PR_fprintf(PR_STDOUT, "unknown CA\n"); break; + case 49: PR_fprintf(PR_STDOUT, "access denied\n"); break; + case 50: PR_fprintf(PR_STDOUT, "decode error\n"); break; + case 51: PR_fprintf(PR_STDOUT, "decrypt error\n"); break; + case 60: PR_fprintf(PR_STDOUT, "export restriction\n"); break; + case 70: PR_fprintf(PR_STDOUT, "protocol version\n"); break; + case 71: PR_fprintf(PR_STDOUT, "insufficient security\n"); break; + case 80: PR_fprintf(PR_STDOUT, "internal error\n"); break; + case 90: PR_fprintf(PR_STDOUT, "user canceled\n"); break; + case 100: PR_fprintf(PR_STDOUT, "no renegotiation\n"); break; + default: PR_fprintf(PR_STDOUT, "unknown error %d\n", tbuf[1]); break; + } + + if (sslhexparse) print_hex(alloclen,tbuf); + break; + + case 22 : /* handshake */ + print_ssl3_handshake( tbuf, alloclen, &sr ); + break; + + case 23 : /* application data */ + default: + print_hex(alloclen,tbuf); + break; + } + } + PR_fprintf(PR_STDOUT,"}\n"); + PR_FREEIF(tbuf); + check_integrity(s); + } +} + +void print_hex(int amt, unsigned char *buf) { + int i,j,k; + char *string = (char*)PR_Malloc(5000); + char t[20]; + + + for(i=0;i<amt;i++) { + t[1] =0; + + if (i%16 ==0) { /* if we are at the beginning of a line */ + PR_fprintf(PR_STDOUT,"%4x:",i); /* print the line number */ + strcpy(string,""); + } + + if (i%4 == 0) { + PR_fprintf(PR_STDOUT," "); + } + + t[0] = buf[i]; + + if (!isprint(t[0])) { + t[0] = '.'; + } + if (fancy) { + switch (t[0]) { + case '<': + strcpy(t,"<"); + break; + case '>': + strcpy(t,">"); + break; + case '&': + strcpy(t,"&"); + break; + } + } + strcat(string,t); + + PR_fprintf(PR_STDOUT,"%02x ",(PRUint8) buf[i]); + + /* if we've reached the end of the line - add the string */ + if (i%16 == 15) PR_fprintf(PR_STDOUT," | %s\n",string); + } + /* we reached the end of the buffer,*/ + /* do we have buffer left over? */ + j = i%16; + if (j > 0) { + for (k=0;k<(16-j);k++) PR_fprintf(PR_STDOUT," "); + PR_fprintf(PR_STDOUT," |%s\n",string); + } + PR_Free(string); +} + +void Usage(void) { + PR_fprintf(PR_STDERR, "SSLTAP (C) 1997, 1998 Netscape Communications Corporation.\n"); + PR_fprintf(PR_STDERR, "Usage: ssltap [-vhfsxl] [-p port] hostname:port\n"); + PR_fprintf(PR_STDERR, " -v [prints version string]\n"); + PR_fprintf(PR_STDERR, " -h [outputs hex instead of ASCII]\n"); + PR_fprintf(PR_STDERR, " -f [turn on Fancy HTML coloring]\n"); + PR_fprintf(PR_STDERR, " -s [turn on SSL decoding]\n"); + PR_fprintf(PR_STDERR, " -x [turn on extra SSL hex dumps]\n"); + PR_fprintf(PR_STDERR, " -p port [specify rendezvous port (default 1924)]\n"); + PR_fprintf(PR_STDERR, " -l [loop - continue to wait for more connections]\n"); + + +} + +void +showErr(const char * msg) { + PRErrorCode err = PR_GetError(); + const char * errString; + + if (err == PR_UNKNOWN_ERROR) + err = PR_CONNECT_RESET_ERROR; /* bug in NSPR. */ + errString = SECU_Strerror(err); + + if (!errString) + errString = "(no text available)"; + PR_fprintf(PR_STDERR, "Error %d: %s: %s", err, errString, msg); +} + +int main(int argc, char *argv[]) +{ + char *hostname=NULL; + PRUint16 rendport=DEFPORT,port; + PRHostEnt hp; + PRStatus r; + PRNetAddr na_client,na_server,na_rend; + PRFileDesc *s_server,*s_client,*s_rend; /*rendezvous */ + char netdbbuf[PR_NETDB_BUF_SIZE]; + int c_count=0; + PLOptState *optstate; + PLOptStatus status; + + optstate = PL_CreateOptState(argc,argv,"fvxhslp:"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case 'f': + fancy++; + break; + case 'h': + hexparse++; + break; + case 'v': + PR_fprintf(PR_STDOUT,"Version: %s\n",VERSIONSTRING); + break; + case 's': + sslparse++; + break; + case 'x': + sslhexparse++; + break; + case 'l': + looparound++; + break; + case 'p': + rendport = atoi(optstate->value); + break; + case '\0': + hostname = PL_strdup(optstate->value); + } + } + if (status == PL_OPT_BAD) + Usage(); + + if (fancy) { + if (!hexparse && !sslparse) { + PR_fprintf(PR_STDERR, +"Note: use of -f without -s or -h not recommended, \n" +"as the output looks a little strange. It may be useful, however\n"); + } + } + + if(! hostname ) Usage(), exit(2); + + { + char *colon = (char *)strchr(hostname, ':'); + if (!colon) { + PR_fprintf(PR_STDERR, + "You must specify the host AND port you wish to connect to\n"); + Usage(), exit(3); + } + port = atoi(&colon[1]); + *colon = '\0'; + + if (port == 0) { + PR_fprintf(PR_STDERR, "Port must be a nonzero number.\n"); + exit(4); + } + } + + /* find the 'server' IP address so we don't have to look it up later */ + + if (fancy) { + PR_fprintf(PR_STDOUT,"<HTML><HEAD><TITLE>SSLTAP output</TITLE></HEAD>\n"); + PR_fprintf(PR_STDOUT,"<BODY><PRE>\n"); + } + PR_fprintf(PR_STDERR,"Looking up \"%s\"...\n", hostname); + r = PR_GetHostByName(hostname,netdbbuf,PR_NETDB_BUF_SIZE,&hp); + if (r) { + showErr("Host Name lookup failed\n"); + exit(5); + } + + PR_EnumerateHostEnt(0,&hp,0,&na_server); + PR_InitializeNetAddr(PR_IpAddrNull,port,&na_server); + /* set up the port which the client will connect to */ + + r = PR_InitializeNetAddr(PR_IpAddrAny,rendport,&na_rend); + if (r == PR_FAILURE) { + PR_fprintf(PR_STDERR, + "PR_InitializeNetAddr(,%d,) failed with error %d\n",PR_GetError()); + exit(0); + } + + + s_rend = PR_NewTCPSocket(); + if (!s_rend) { + showErr("Couldn't create socket\n"); + exit(6); + } + + if (PR_Bind(s_rend, &na_rend )) { + PR_fprintf(PR_STDERR,"Couldn't bind to port %d (error %d)\n",rendport, PR_GetError()); + exit(-1); + } + + if ( PR_Listen(s_rend, 5)) { + showErr("Couldn't listen\n"); + exit(-1); + } + + PR_fprintf(PR_STDERR,"Proxy socket ready and listening\n"); + do { /* accept one connection and process it. */ + PRPollDesc pds[2]; + + s_client = PR_Accept(s_rend,&na_client,PR_SecondsToInterval(3600)); + if (s_client == NULL) { + showErr("accept timed out\n"); + exit(7); + } + + s_server = PR_NewTCPSocket(); + if (s_server == NULL) { + showErr("couldn't open new socket to connect to server \n"); + exit(8); + } + + r = PR_Connect(s_server,&na_server,PR_SecondsToInterval(5)); + + if ( r == PR_FAILURE ) + { + showErr("Couldn't connect\n"); + return -1; + } + + if (looparound) { + if (fancy) PR_fprintf(PR_STDOUT,"<p><HR><H2>"); + PR_fprintf(PR_STDOUT,"Connection #%d [%s]\n", c_count+1, + get_time_string()); + if (fancy) PR_fprintf(PR_STDOUT,"</H2>"); + } + + + PR_fprintf(PR_STDOUT,"Connected to %s:%d\n", hostname, port); + +#define PD_C 0 +#define PD_S 1 + + pds[PD_C].fd = s_client; + pds[PD_S].fd = s_server; + pds[PD_C].in_flags = PR_POLL_READ; + pds[PD_S].in_flags = PR_POLL_READ; + + /* make sure the new connections don't start out encrypted. */ + clientstream.isEncrypted = 0; + serverstream.isEncrypted = 0; + isV2Session = 0; + + while( (pds[PD_C].in_flags & PR_POLL_READ) != 0 || + (pds[PD_S].in_flags & PR_POLL_READ) != 0 ) + { /* Handle all messages on the connection */ + PRInt32 amt; + PRInt32 wrote; + unsigned char buffer[ TAPBUFSIZ ]; + + amt = PR_Poll(pds,2,PR_INTERVAL_NO_TIMEOUT); + if (amt <= 0) { + if (amt) + showErr( "PR_Poll failed.\n"); + else + showErr( "PR_Poll timed out.\n"); + break; + } + + if (pds[PD_C].out_flags & PR_POLL_EXCEPT) { + showErr( "Exception on client-side socket.\n"); + break; + } + + if (pds[PD_S].out_flags & PR_POLL_EXCEPT) { + showErr( "Exception on server-side socket.\n"); + break; + } + + +/* read data, copy it to stdout, and write to other socket */ + + if ((pds[PD_C].in_flags & PR_POLL_READ) != 0 && + (pds[PD_C].out_flags & PR_POLL_READ) != 0 ) { + + amt = PR_Read(s_client, buffer, sizeof(buffer)); + + if ( amt < 0) { + showErr( "Client socket read failed.\n"); + break; + } + + if( amt == 0 ) { + PR_fprintf(PR_STDOUT, "Read EOF on Client socket. [%s]\n", + get_time_string() ); + pds[PD_C].in_flags &= ~PR_POLL_READ; + PR_Shutdown(s_server, PR_SHUTDOWN_SEND); + continue; + } + + PR_fprintf(PR_STDOUT,"--> [\n"); + if (fancy) PR_fprintf(PR_STDOUT,"<font color=blue>"); + + if (hexparse) print_hex(amt, buffer); + if (sslparse) print_ssl(&clientstream,amt,buffer); + if (!hexparse && !sslparse) PR_Write(PR_STDOUT,buffer,amt); + if (fancy) PR_fprintf(PR_STDOUT,"</font>"); + PR_fprintf(PR_STDOUT,"]\n"); + + wrote = PR_Write(s_server, buffer, amt); + if (wrote != amt ) { + if (wrote < 0) { + showErr("Write to server socket failed.\n"); + break; + } else { + PR_fprintf(PR_STDERR, "Short write to server socket!\n"); + } + } + } /* end of read from client socket. */ + +/* read data, copy it to stdout, and write to other socket */ + if ((pds[PD_S].in_flags & PR_POLL_READ) != 0 && + (pds[PD_S].out_flags & PR_POLL_READ) != 0 ) { + + amt = PR_Read(s_server, buffer, sizeof(buffer)); + + if ( amt < 0) { + showErr( "error on server-side socket.\n"); + break; + } + + if( amt == 0 ) { + PR_fprintf(PR_STDOUT, "Read EOF on Server socket. [%s]\n", + get_time_string() ); + pds[PD_S].in_flags &= ~PR_POLL_READ; + PR_Shutdown(s_client, PR_SHUTDOWN_SEND); + continue; + } + + PR_fprintf(PR_STDOUT,"<-- [\n"); + if (fancy) PR_fprintf(PR_STDOUT,"<font color=red>"); + if (hexparse) print_hex(amt, (unsigned char *)buffer); + if (sslparse) print_ssl(&serverstream,amt,(unsigned char *)buffer); + if (!hexparse && !sslparse) PR_Write(PR_STDOUT,buffer,amt); + if (fancy) PR_fprintf(PR_STDOUT,"</font>"); + PR_fprintf(PR_STDOUT,"]\n"); + + + wrote = PR_Write(s_client, buffer, amt); + if (wrote != amt ) { + if (wrote < 0) { + showErr("Write to client socket failed.\n"); + break; + } else { + PR_fprintf(PR_STDERR, "Short write to client socket!\n"); + } + } + + } /* end of read from server socket. */ + +/* Loop, handle next message. */ + + } /* handle messages during a connection loop */ + PR_Close(s_client); + PR_Close(s_server); + flush_stream(&clientstream); + flush_stream(&serverstream); + + c_count++; + PR_fprintf(PR_STDERR,"Connection %d Complete [%s]\n", c_count, + get_time_string() ); + } while (looparound); /* accept connection and process it. */ + PR_Close(s_rend); + return 0; +} diff --git a/security/nss/cmd/strsclnt/Makefile b/security/nss/cmd/strsclnt/Makefile new file mode 100644 index 000000000..4e39ffc3f --- /dev/null +++ b/security/nss/cmd/strsclnt/Makefile @@ -0,0 +1,75 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/strsclnt/manifest.mn b/security/nss/cmd/strsclnt/manifest.mn new file mode 100644 index 000000000..e54345f6d --- /dev/null +++ b/security/nss/cmd/strsclnt/manifest.mn @@ -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. +# +CORE_DEPTH = ../../.. + +DEFINES += -DNSPR20 + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +CSRCS = strsclnt.c + +# the MODULE above is always implicitly REQUIREd +REQUIRES = seccmd dbm + +PROGRAM = strsclnt +# PROGRAM = ./$(OBJDIR)/strsclnt.exe + diff --git a/security/nss/cmd/strsclnt/strsclnt.c b/security/nss/cmd/strsclnt/strsclnt.c new file mode 100644 index 000000000..ae20c02bb --- /dev/null +++ b/security/nss/cmd/strsclnt/strsclnt.c @@ -0,0 +1,1175 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "secutil.h" + +#if defined(XP_UNIX) +#include <unistd.h> +#endif +#include <stdlib.h> +#if !defined(_WIN32_WCE) +#include <errno.h> +#include <fcntl.h> +#endif +#include <stdarg.h> + +#include "plgetopt.h" + +#include "nspr.h" +#include "prio.h" +#include "prnetdb.h" +#include "prerror.h" + +#include "pk11func.h" +#include "secitem.h" +#include "sslproto.h" +#include "nss.h" +#include "ssl.h" + +#ifndef PORT_Sprintf +#define PORT_Sprintf sprintf +#endif + +#ifndef PORT_Strstr +#define PORT_Strstr strstr +#endif + +#ifndef PORT_Malloc +#define PORT_Malloc PR_Malloc +#endif + +#define RD_BUF_SIZE (60 * 1024) + +/* Include these cipher suite arrays to re-use tstclnt's + * cipher selection code. + */ + +int ssl2CipherSuites[] = { + SSL_EN_RC4_128_WITH_MD5, /* A */ + SSL_EN_RC4_128_EXPORT40_WITH_MD5, /* B */ + SSL_EN_RC2_128_CBC_WITH_MD5, /* C */ + SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */ + SSL_EN_DES_64_CBC_WITH_MD5, /* E */ + SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* F */ +#ifdef NSS_ENABLE_ECC + /* NOTE: Since no new SSL2 ciphersuites are being + * invented, and we've run out of lowercase letters + * for SSL3 ciphers, we use letters G and beyond + * for new SSL3 ciphers. + */ + TLS_ECDH_ECDSA_WITH_NULL_SHA, /* G */ + TLS_ECDH_ECDSA_WITH_RC4_128_SHA, /* H */ + TLS_ECDH_ECDSA_WITH_DES_CBC_SHA, /* I */ + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, /* J */ + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, /* K */ + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, /* L */ + TLS_ECDH_RSA_WITH_NULL_SHA, /* M */ + TLS_ECDH_RSA_WITH_RC4_128_SHA, /* N */ + TLS_ECDH_RSA_WITH_DES_CBC_SHA, /* O */ + TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, /* P */ + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, /* Q */ + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, /* R */ + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* S */ + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* T */ +#endif /* NSS_ENABLE_ECC */ + 0 +}; + +int ssl3CipherSuites[] = { + SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, /* a */ + SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, /* b */ + SSL_RSA_WITH_RC4_128_MD5, /* c */ + SSL_RSA_WITH_3DES_EDE_CBC_SHA, /* d */ + SSL_RSA_WITH_DES_CBC_SHA, /* e */ + SSL_RSA_EXPORT_WITH_RC4_40_MD5, /* f */ + SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* g */ + SSL_FORTEZZA_DMS_WITH_NULL_SHA, /* h */ + SSL_RSA_WITH_NULL_MD5, /* i */ + SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, /* j */ + SSL_RSA_FIPS_WITH_DES_CBC_SHA, /* k */ + TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, /* l */ + TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, /* m */ + SSL_RSA_WITH_RC4_128_SHA, /* n */ + TLS_DHE_DSS_WITH_RC4_128_SHA, /* o */ + SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, /* p */ + SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, /* q */ + SSL_DHE_RSA_WITH_DES_CBC_SHA, /* r */ + SSL_DHE_DSS_WITH_DES_CBC_SHA, /* s */ + TLS_DHE_DSS_WITH_AES_128_CBC_SHA, /* t */ + TLS_DHE_RSA_WITH_AES_128_CBC_SHA, /* u */ + TLS_RSA_WITH_AES_128_CBC_SHA, /* v */ + TLS_DHE_DSS_WITH_AES_256_CBC_SHA, /* w */ + TLS_DHE_RSA_WITH_AES_256_CBC_SHA, /* x */ + TLS_RSA_WITH_AES_256_CBC_SHA, /* y */ + 0 +}; + +/* This global string is so that client main can see + * which ciphers to use. + */ + +static const char *cipherString; + +static int certsTested; +static int MakeCertOK; +static int NoReuse; +static PRBool NoDelay; +static PRBool QuitOnTimeout = PR_FALSE; + +static SSL3Statistics * ssl3stats; + +static int failed_already = 0; + + +char * ownPasswd( PK11SlotInfo *slot, PRBool retry, void *arg) +{ + char *passwd = NULL; + + if ( (!retry) && arg ) { + passwd = PL_strdup((char *)arg); + } + + return passwd; +} + +int stopping; +int verbose; +SECItem bigBuf; + +#define PRINTF if (verbose) printf +#define FPRINTF if (verbose) fprintf + +static void +Usage(const char *progName) +{ + fprintf(stderr, + "Usage: %s [-n rsa_nickname] [-p port] [-d dbdir] [-c connections]\n" + " [-DNvq] [-f fortezza_nickname] [-2 filename]\n" + " [-w dbpasswd] [-C cipher(s)] [-t threads] hostname\n" + " where -v means verbose\n" + " -D means no TCP delays\n" + " -q means quit when server gone (timeout rather than retry forever)\n" + " -N means no session reuse\n", + progName); + exit(1); +} + + +static void +errWarn(char * funcString) +{ + PRErrorCode perr = PR_GetError(); + const char * errString = SECU_Strerror(perr); + + fprintf(stderr, "strsclnt: %s returned error %d:\n%s\n", + funcString, perr, errString); +} + +static void +errExit(char * funcString) +{ + errWarn(funcString); + exit(1); +} + +/************************************************************************** +** +** Routines for disabling SSL ciphers. +** +**************************************************************************/ + +void +disableAllSSLCiphers(void) +{ + const PRUint16 *cipherSuites = SSL_ImplementedCiphers; + int i = SSL_NumImplementedCiphers; + SECStatus rv; + + /* disable all the SSL3 cipher suites */ + while (--i >= 0) { + PRUint16 suite = cipherSuites[i]; + rv = SSL_CipherPrefSetDefault(suite, PR_FALSE); + if (rv != SECSuccess) { + printf("SSL_CipherPrefSetDefault didn't like value 0x%04x (i = %d)\n", + suite, i); + errWarn("SSL_CipherPrefSetDefault"); + exit(2); + } + } +} + +/* This invokes the "default" AuthCert handler in libssl. +** The only reason to use this one is that it prints out info as it goes. +*/ +static SECStatus +mySSLAuthCertificate(void *arg, PRFileDesc *fd, PRBool checkSig, + PRBool isServer) +{ + SECStatus rv; + CERTCertificate * peerCert; + + peerCert = SSL_PeerCertificate(fd); + + PRINTF("strsclnt: Subject: %s\nstrsclnt: Issuer : %s\n", + peerCert->subjectName, peerCert->issuerName); + /* invoke the "default" AuthCert handler. */ + rv = SSL_AuthCertificate(arg, fd, checkSig, isServer); + + ++certsTested; + if (rv == SECSuccess) { + fputs("strsclnt: -- SSL: Server Certificate Validated.\n", stderr); + } + CERT_DestroyCertificate(peerCert); + /* error, if any, will be displayed by the Bad Cert Handler. */ + return rv; +} + +static SECStatus +myBadCertHandler( void *arg, PRFileDesc *fd) +{ + int err = PR_GetError(); + if (!MakeCertOK) + fprintf(stderr, + "strsclnt: -- SSL: Server Certificate Invalid, err %d.\n%s\n", + err, SECU_Strerror(err)); + return (MakeCertOK ? SECSuccess : SECFailure); +} + +void +printSecurityInfo(PRFileDesc *fd) +{ + CERTCertificate * cert = NULL; + SSL3Statistics * ssl3stats = SSL_GetStatistics(); + SECStatus result; + SSLChannelInfo channel; + SSLCipherSuiteInfo suite; + + static int only_once; + + if (only_once && verbose < 2) + return; + only_once = 1; + + result = SSL_GetChannelInfo(fd, &channel, sizeof channel); + if (result == SECSuccess && + channel.length == sizeof channel && + channel.cipherSuite) { + result = SSL_GetCipherSuiteInfo(channel.cipherSuite, + &suite, sizeof suite); + if (result == SECSuccess) { + FPRINTF(stderr, + "strsclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n", + channel.protocolVersion >> 8, channel.protocolVersion & 0xff, + suite.effectiveKeyBits, suite.symCipherName, + suite.macBits, suite.macAlgorithmName); + FPRINTF(stderr, + "strsclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n", + channel.authKeyBits, suite.authAlgorithmName, + channel.keaKeyBits, suite.keaTypeName); + } + } + + cert = SSL_LocalCertificate(fd); + if (!cert) + cert = SSL_PeerCertificate(fd); + + if (verbose && cert) { + char * ip = CERT_NameToAscii(&cert->issuer); + char * sp = CERT_NameToAscii(&cert->subject); + if (sp) { + fprintf(stderr, "strsclnt: subject DN: %s\n", sp); + PR_Free(sp); + } + if (ip) { + fprintf(stderr, "strsclnt: issuer DN: %s\n", ip); + PR_Free(ip); + } + } + if (cert) { + CERT_DestroyCertificate(cert); + cert = NULL; + } + fprintf(stderr, + "strsclnt: %ld cache hits; %ld cache misses, %ld cache not reusable\n", + ssl3stats->hsh_sid_cache_hits, + ssl3stats->hsh_sid_cache_misses, + ssl3stats->hsh_sid_cache_not_ok); + +} + +/************************************************************************** +** Begin thread management routines and data. +**************************************************************************/ + +#define MAX_THREADS 128 + +typedef int startFn(void *a, void *b, int c); + +PRLock * threadLock; +PRCondVar * threadStartQ; +PRCondVar * threadEndQ; + +int numUsed; +int numRunning; +PRInt32 numConnected; +int max_threads = 8; /* default much less than max. */ + +typedef enum { rs_idle = 0, rs_running = 1, rs_zombie = 2 } runState; + +typedef struct perThreadStr { + void * a; + void * b; + int c; + int rv; + startFn * startFunc; + PRThread * prThread; + PRBool inUse; + runState running; +} perThread; + +perThread threads[MAX_THREADS]; + +void +thread_wrapper(void * arg) +{ + perThread * slot = (perThread *)arg; + + /* wait for parent to finish launching us before proceeding. */ + PR_Lock(threadLock); + PR_Unlock(threadLock); + + slot->rv = (* slot->startFunc)(slot->a, slot->b, slot->c); + + /* Handle cleanup of thread here. */ + PRINTF("strsclnt: Thread in slot %d returned %d\n", + slot - threads, slot->rv); + + PR_Lock(threadLock); + slot->running = rs_idle; + --numRunning; + + /* notify the thread launcher. */ + PR_NotifyCondVar(threadStartQ); + + PR_Unlock(threadLock); +} + +SECStatus +launch_thread( + startFn * startFunc, + void * a, + void * b, + int c) +{ + perThread * slot; + int i; + + if (!threadStartQ) { + threadLock = PR_NewLock(); + threadStartQ = PR_NewCondVar(threadLock); + threadEndQ = PR_NewCondVar(threadLock); + } + PR_Lock(threadLock); + while (numRunning >= max_threads) { + PR_WaitCondVar(threadStartQ, PR_INTERVAL_NO_TIMEOUT); + } + for (i = 0; i < numUsed; ++i) { + if (threads[i].running == rs_idle) + break; + } + if (i >= numUsed) { + if (i >= MAX_THREADS) { + /* something's really wrong here. */ + PORT_Assert(i < MAX_THREADS); + PR_Unlock(threadLock); + return SECFailure; + } + ++numUsed; + PORT_Assert(numUsed == i + 1); + } + + slot = threads + i; + slot->a = a; + slot->b = b; + slot->c = c; + + slot->startFunc = startFunc; + + slot->prThread = PR_CreateThread(PR_USER_THREAD, + thread_wrapper, slot, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, + PR_UNJOINABLE_THREAD, 0); + if (slot->prThread == NULL) { + PR_Unlock(threadLock); + printf("strsclnt: Failed to launch thread!\n"); + return SECFailure; + } + + slot->inUse = 1; + slot->running = 1; + ++numRunning; + PR_Unlock(threadLock); + PRINTF("strsclnt: Launched thread in slot %d \n", i); + + return SECSuccess; +} + +/* Wait until numRunning == 0 */ +int +reap_threads(void) +{ + perThread * slot; + int i; + + if (!threadLock) + return 0; + PR_Lock(threadLock); + while (numRunning > 0) { + PR_WaitCondVar(threadStartQ, PR_INTERVAL_NO_TIMEOUT); + } + + /* Safety Sam sez: make sure count is right. */ + for (i = 0; i < numUsed; ++i) { + slot = threads + i; + if (slot->running != rs_idle) { + FPRINTF(stderr, "strsclnt: Thread in slot %d is in state %d!\n", + i, slot->running); + } + } + PR_Unlock(threadLock); + return 0; +} + +void +destroy_thread_data(void) +{ + PORT_Memset(threads, 0, sizeof threads); + + if (threadEndQ) { + PR_DestroyCondVar(threadEndQ); + threadEndQ = NULL; + } + if (threadStartQ) { + PR_DestroyCondVar(threadStartQ); + threadStartQ = NULL; + } + if (threadLock) { + PR_DestroyLock(threadLock); + threadLock = NULL; + } +} + +/************************************************************************** +** End thread management routines. +**************************************************************************/ + +PRBool useModelSocket = PR_TRUE; + +static const char stopCmd[] = { "GET /stop " }; +static const char outHeader[] = { + "HTTP/1.0 200 OK\r\n" + "Server: Netscape-Enterprise/2.0a\r\n" + "Date: Tue, 26 Aug 1997 22:10:05 GMT\r\n" + "Content-type: text/plain\r\n" + "\r\n" +}; + +struct lockedVarsStr { + PRLock * lock; + int count; + int waiters; + PRCondVar * condVar; +}; + +typedef struct lockedVarsStr lockedVars; + +void +lockedVars_Init( lockedVars * lv) +{ + lv->count = 0; + lv->waiters = 0; + lv->lock = PR_NewLock(); + lv->condVar = PR_NewCondVar(lv->lock); +} + +void +lockedVars_Destroy( lockedVars * lv) +{ + PR_DestroyCondVar(lv->condVar); + lv->condVar = NULL; + + PR_DestroyLock(lv->lock); + lv->lock = NULL; +} + +void +lockedVars_WaitForDone(lockedVars * lv) +{ + PR_Lock(lv->lock); + while (lv->count > 0) { + PR_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(lv->lock); +} + +int /* returns count */ +lockedVars_AddToCount(lockedVars * lv, int addend) +{ + int rv; + + PR_Lock(lv->lock); + rv = lv->count += addend; + if (rv <= 0) { + PR_NotifyCondVar(lv->condVar); + } + PR_Unlock(lv->lock); + return rv; +} + +int +do_writes( + void * a, + void * b, + int c) +{ + PRFileDesc * ssl_sock = (PRFileDesc *)a; + lockedVars * lv = (lockedVars *)b; + int sent = 0; + int count = 0; + + while (sent < bigBuf.len) { + + count = PR_Write(ssl_sock, bigBuf.data + sent, bigBuf.len - sent); + if (count < 0) { + errWarn("PR_Write bigBuf"); + break; + } + FPRINTF(stderr, "strsclnt: PR_Write wrote %d bytes from bigBuf\n", + count ); + sent += count; + } + if (count >= 0) { /* last write didn't fail. */ + PR_Shutdown(ssl_sock, PR_SHUTDOWN_SEND); + } + + /* notify the reader that we're done. */ + lockedVars_AddToCount(lv, -1); + return (sent < bigBuf.len) ? SECFailure : SECSuccess; +} + +int +handle_fdx_connection( PRFileDesc * ssl_sock, int connection) +{ + SECStatus result; + int firstTime = 1; + int countRead = 0; + lockedVars lv; + char *buf; + + + lockedVars_Init(&lv); + lockedVars_AddToCount(&lv, 1); + + /* Attempt to launch the writer thread. */ + result = launch_thread(do_writes, ssl_sock, &lv, connection); + + if (result != SECSuccess) + goto cleanup; + + buf = PR_Malloc(RD_BUF_SIZE); + + if (buf) { + do { + /* do reads here. */ + PRInt32 count; + + count = PR_Read(ssl_sock, buf, RD_BUF_SIZE); + if (count < 0) { + errWarn("PR_Read"); + break; + } + countRead += count; + FPRINTF(stderr, + "strsclnt: connection %d read %d bytes (%d total).\n", + connection, count, countRead ); + if (firstTime) { + firstTime = 0; + printSecurityInfo(ssl_sock); + } + } while (lockedVars_AddToCount(&lv, 0) > 0); + PR_Free(buf); + buf = 0; + } + + /* Wait for writer to finish */ + lockedVars_WaitForDone(&lv); + lockedVars_Destroy(&lv); + + FPRINTF(stderr, + "strsclnt: connection %d read %d bytes total. -----------------------\n", + connection, countRead); + +cleanup: + /* Caller closes the socket. */ + + return SECSuccess; +} + +const char request[] = {"GET /abc HTTP/1.0\r\n\r\n" }; + +SECStatus +handle_connection( PRFileDesc *ssl_sock, int connection) +{ + int countRead = 0; + PRInt32 rv; + char *buf; + + buf = PR_Malloc(RD_BUF_SIZE); + if (!buf) + return SECFailure; + + /* compose the http request here. */ + + rv = PR_Write(ssl_sock, request, strlen(request)); + if (rv <= 0) { + errWarn("PR_Write"); + PR_Free(buf); + buf = 0; + failed_already = 1; + return SECFailure; + } + printSecurityInfo(ssl_sock); + + /* read until EOF */ + while (1) { + rv = PR_Read(ssl_sock, buf, RD_BUF_SIZE); + if (rv == 0) { + break; /* EOF */ + } + if (rv < 0) { + errWarn("PR_Read"); + break; + } + + countRead += rv; + FPRINTF(stderr, "strsclnt: connection %d read %d bytes (%d total).\n", + connection, rv, countRead ); + } + PR_Free(buf); + buf = 0; + + /* Caller closes the socket. */ + + FPRINTF(stderr, + "strsclnt: connection %d read %d bytes total. -----------------------\n", + connection, countRead); + + return SECSuccess; /* success */ +} + +/* one copy of this function is launched in a separate thread for each +** connection to be made. +*/ +int +do_connects( + void * a, + void * b, + int connection) +{ + PRNetAddr * addr = (PRNetAddr *) a; + PRFileDesc * model_sock = (PRFileDesc *) b; + PRFileDesc * ssl_sock = 0; + PRFileDesc * tcp_sock = 0; + PRStatus prStatus; + PRUint32 sleepInterval = 50; /* milliseconds */ + SECStatus result; + int rv = SECSuccess; + PRSocketOptionData opt; + +retry: + + tcp_sock = PR_NewTCPSocket(); + if (tcp_sock == NULL) { + errExit("PR_NewTCPSocket"); + } + + opt.option = PR_SockOpt_Nonblocking; + opt.value.non_blocking = PR_FALSE; + prStatus = PR_SetSocketOption(tcp_sock, &opt); + if (prStatus != PR_SUCCESS) { + errWarn("PR_SetSocketOption(PR_SockOpt_Nonblocking, PR_FALSE)"); + PR_Close(tcp_sock); + return SECSuccess; + } + + if (NoDelay) { + opt.option = PR_SockOpt_NoDelay; + opt.value.no_delay = PR_TRUE; + prStatus = PR_SetSocketOption(tcp_sock, &opt); + if (prStatus != PR_SUCCESS) { + errWarn("PR_SetSocketOption(PR_SockOpt_NoDelay, PR_TRUE)"); + PR_Close(tcp_sock); + return SECSuccess; + } + } + + prStatus = PR_Connect(tcp_sock, addr, PR_INTERVAL_NO_TIMEOUT); + if (prStatus != PR_SUCCESS) { + PRErrorCode err = PR_GetError(); + if ((err == PR_CONNECT_REFUSED_ERROR) || + (err == PR_CONNECT_RESET_ERROR) ) { + int connections = numConnected; + + PR_Close(tcp_sock); + if (connections > 2 && max_threads >= connections) { + max_threads = connections - 1; + fprintf(stderr,"max_threads set down to %d\n", max_threads); + } + if (QuitOnTimeout && sleepInterval > 40000) { + fprintf(stderr, + "strsclnt: Client timed out waiting for connection to server.\n"); + exit(1); + } + PR_Sleep(PR_MillisecondsToInterval(sleepInterval)); + sleepInterval <<= 1; + goto retry; + } + errWarn("PR_Connect"); + rv = SECFailure; + goto done; + } + + ssl_sock = SSL_ImportFD(model_sock, tcp_sock); + /* XXX if this import fails, close tcp_sock and return. */ + if (!ssl_sock) { + PR_Close(tcp_sock); + return SECSuccess; + } + + rv = SSL_ResetHandshake(ssl_sock, /* asServer */ 0); + if (rv != SECSuccess) { + errWarn("SSL_ResetHandshake"); + goto done; + } + + PR_AtomicIncrement(&numConnected); + + if (bigBuf.data != NULL) { + result = handle_fdx_connection( ssl_sock, connection); + } else { + result = handle_connection( ssl_sock, connection); + } + + PR_AtomicDecrement(&numConnected); + +done: + if (ssl_sock) { + PR_Close(ssl_sock); + } else if (tcp_sock) { + PR_Close(tcp_sock); + } + return SECSuccess; +} + +/* Returns IP address for hostname as PRUint32 in Host Byte Order. +** Since the value returned is an integer (not a string of bytes), +** it is inherently in Host Byte Order. +*/ +PRUint32 +getIPAddress(const char * hostName) +{ + const unsigned char *p; + PRStatus prStatus; + PRUint32 rv; + PRHostEnt prHostEnt; + char scratch[PR_NETDB_BUF_SIZE]; + + prStatus = PR_GetHostByName(hostName, scratch, sizeof scratch, &prHostEnt); + if (prStatus != PR_SUCCESS) + errExit("PR_GetHostByName"); + +#undef h_addr +#define h_addr h_addr_list[0] /* address, for backward compatibility */ + + p = (const unsigned char *)(prHostEnt.h_addr); /* in Network Byte order */ + FPRINTF(stderr, "strsclnt: %s -> %d.%d.%d.%d\n", hostName, + p[0], p[1], p[2], p[3]); + rv = (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3]; + return rv; +} + +void +client_main( + unsigned short port, + int connections, + SECKEYPrivateKey ** privKey, + CERTCertificate ** cert, + const char * hostName, + char * nickName) +{ + PRFileDesc *model_sock = NULL; + int i; + int rv; + PRUint32 ipAddress; /* in host byte order */ + PRNetAddr addr; + + /* Assemble NetAddr struct for connections. */ + ipAddress = getIPAddress(hostName); + + addr.inet.family = PR_AF_INET; + addr.inet.port = PR_htons(port); + addr.inet.ip = PR_htonl(ipAddress); + + /* all suites except RSA_NULL_MD5 are enabled by Domestic Policy */ + NSS_SetDomesticPolicy(); + + /* all the SSL2 and SSL3 cipher suites are enabled by default. */ + if (cipherString) { + int ndx; + + /* disable all the ciphers, then enable the ones we want. */ + disableAllSSLCiphers(); + + while (0 != (ndx = *cipherString++)) { + int *cptr; + int cipher; + + if (! isalpha(ndx)) + Usage("strsclnt"); + cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites; + for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; ) + /* do nothing */; + if (cipher) { + SECStatus rv; + rv = SSL_CipherPrefSetDefault(cipher, PR_TRUE); + if (rv != SECSuccess) { + fprintf(stderr, + "strsclnt: SSL_CipherPrefSetDefault failed with value 0x%04x\n", + cipher); + exit(1); + } + } + } + } + + /* configure model SSL socket. */ + + model_sock = PR_NewTCPSocket(); + if (model_sock == NULL) { + errExit("PR_NewTCPSocket on model socket"); + } + + model_sock = SSL_ImportFD(NULL, model_sock); + if (model_sock == NULL) { + errExit("SSL_ImportFD"); + } + + /* do SSL configuration. */ + + rv = SSL_OptionSet(model_sock, SSL_SECURITY, 1); + if (rv < 0) { + errExit("SSL_OptionSet SSL_SECURITY"); + } + + if (bigBuf.data) { /* doing FDX */ + rv = SSL_OptionSet(model_sock, SSL_ENABLE_FDX, 1); + if (rv < 0) { + errExit("SSL_OptionSet SSL_ENABLE_FDX"); + } + } + + if (NoReuse) { + rv = SSL_OptionSet(model_sock, SSL_NO_CACHE, 1); + if (rv < 0) { + errExit("SSL_OptionSet SSL_NO_CACHE"); + } + } + + SSL_SetURL(model_sock, hostName); + + SSL_AuthCertificateHook(model_sock, mySSLAuthCertificate, + (void *)CERT_GetDefaultCertDB()); + + SSL_BadCertHook(model_sock, myBadCertHandler, NULL); + + SSL_GetClientAuthDataHook(model_sock, NSS_GetClientAuthData, nickName); + + /* I'm not going to set the HandshakeCallback function. */ + + /* end of ssl configuration. */ + + i = 1; + if (!NoReuse) { + rv = launch_thread(do_connects, &addr, model_sock, i); + --connections; + ++i; + /* wait for the first connection to terminate, then launch the rest. */ + reap_threads(); + } + if (connections > 0) { + /* Start up the connections */ + do { + rv = launch_thread(do_connects, &addr, model_sock, i); + ++i; + } while (--connections > 0); + reap_threads(); + } + destroy_thread_data(); + + PR_Close(model_sock); + +} + +SECStatus +readBigFile(const char * fileName) +{ + PRFileInfo info; + PRStatus status; + SECStatus rv = SECFailure; + int count; + int hdrLen; + PRFileDesc *local_file_fd = NULL; + + status = PR_GetFileInfo(fileName, &info); + + if (status == PR_SUCCESS && + info.type == PR_FILE_FILE && + info.size > 0 && + NULL != (local_file_fd = PR_Open(fileName, PR_RDONLY, 0))) { + + hdrLen = PORT_Strlen(outHeader); + bigBuf.len = hdrLen + info.size; + bigBuf.data = PORT_Malloc(bigBuf.len + 4095); + if (!bigBuf.data) { + errWarn("PORT_Malloc"); + goto done; + } + + PORT_Memcpy(bigBuf.data, outHeader, hdrLen); + + count = PR_Read(local_file_fd, bigBuf.data + hdrLen, info.size); + if (count != info.size) { + errWarn("PR_Read local file"); + goto done; + } + rv = SECSuccess; +done: + PR_Close(local_file_fd); + } + return rv; +} + +int +main(int argc, char **argv) +{ + const char * dir = "."; + char * fNickName = NULL; + const char * fileName = NULL; + char * hostName = NULL; + char * nickName = NULL; + char * progName = NULL; + char * tmp = NULL; + char * passwd = NULL; + CERTCertificate * cert [kt_kea_size] = { NULL }; + SECKEYPrivateKey * privKey[kt_kea_size] = { NULL }; + int connections = 1; + int exitVal; + int tmpInt; + unsigned short port = 443; + SECStatus rv; + PLOptState * optstate; + PLOptStatus status; + + /* Call the NSPR initialization routines */ + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + + tmp = strrchr(argv[0], '/'); + tmp = tmp ? tmp + 1 : argv[0]; + progName = strrchr(tmp, '\\'); + progName = progName ? progName + 1 : tmp; + + + optstate = PL_CreateOptState(argc, argv, "2:C:DNc:d:f:n:op:t:vqw:"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch(optstate->option) { + + case '2': fileName = optstate->value; break; + + case 'C': cipherString = optstate->value; break; + + case 'D': NoDelay = PR_TRUE; break; + + case 'N': NoReuse = 1; break; + + case 'c': connections = PORT_Atoi(optstate->value); break; + + case 'd': dir = optstate->value; break; + + case 'f': fNickName = PL_strdup(optstate->value); break; + + case 'n': nickName = PL_strdup(optstate->value); break; + + case 'o': MakeCertOK = 1; break; + + case 'p': port = PORT_Atoi(optstate->value); break; + + case 'q': QuitOnTimeout = PR_TRUE; break; + + case 't': + tmpInt = PORT_Atoi(optstate->value); + if (tmpInt > 0 && tmpInt < MAX_THREADS) + max_threads = tmpInt; + break; + + case 'v': verbose++; break; + + case 'w': passwd = PL_strdup(optstate->value); break; + + case 0: /* positional parameter */ + if (hostName) { + Usage(progName); + } + hostName = PL_strdup(optstate->value); + break; + + default: + case '?': + Usage(progName); + break; + + } + } + if (!hostName || status == PL_OPT_BAD) + Usage(progName); + + if (port == 0) + Usage(progName); + + if (fileName) + readBigFile(fileName); + + /* set our password function */ + if ( passwd ) { + PK11_SetPasswordFunc(ownPasswd); + } else { + PK11_SetPasswordFunc(SECU_GetModulePassword); + } + + /* Call the libsec initialization routines */ + rv = NSS_Init(dir); + if (rv != SECSuccess) { + fputs("NSS_Init failed.\n", stderr); + exit(1); + } + ssl3stats = SSL_GetStatistics(); + + if (nickName && strcmp(nickName, "none")) { + + cert[kt_rsa] = PK11_FindCertFromNickname(nickName, passwd); + if (cert[kt_rsa] == NULL) { + fprintf(stderr, "strsclnt: Can't find certificate %s\n", nickName); + exit(1); + } + + privKey[kt_rsa] = PK11_FindKeyByAnyCert(cert[kt_rsa], passwd); + if (privKey[kt_rsa] == NULL) { + fprintf(stderr, "strsclnt: Can't find Private Key for cert %s\n", + nickName); + exit(1); + } + + } + if (fNickName) { + cert[kt_fortezza] = PK11_FindCertFromNickname(fNickName, passwd); + if (cert[kt_fortezza] == NULL) { + fprintf(stderr, "strsclnt: Can't find certificate %s\n", fNickName); + exit(1); + } + + privKey[kt_fortezza] = PK11_FindKeyByAnyCert(cert[kt_fortezza], passwd); + if (privKey[kt_fortezza] == NULL) { + fprintf(stderr, "strsclnt: Can't find Private Key for cert %s\n", + fNickName); + exit(1); + } + } + + client_main(port, connections, privKey, cert, hostName, nickName); + + /* clean up */ + if (cert[kt_rsa]) { + CERT_DestroyCertificate(cert[kt_rsa]); + } + if (cert[kt_fortezza]) { + CERT_DestroyCertificate(cert[kt_fortezza]); + } + if (privKey[kt_rsa]) { + SECKEY_DestroyPrivateKey(privKey[kt_rsa]); + } + if (privKey[kt_fortezza]) { + SECKEY_DestroyPrivateKey(privKey[kt_fortezza]); + } + + /* some final stats. */ + if (ssl3stats->hsh_sid_cache_hits + ssl3stats->hsh_sid_cache_misses + + ssl3stats->hsh_sid_cache_not_ok == 0) { + /* presumably we were testing SSL2. */ + printf("strsclnt: %d server certificates tested.\n", certsTested); + } else { + printf( + "strsclnt: %ld cache hits; %ld cache misses, %ld cache not reusable\n", + ssl3stats->hsh_sid_cache_hits, + ssl3stats->hsh_sid_cache_misses, + ssl3stats->hsh_sid_cache_not_ok); + } + + if (!NoReuse) + exitVal = (ssl3stats->hsh_sid_cache_misses > 1) || + (ssl3stats->hsh_sid_cache_not_ok != 0) || + (certsTested > 1); + else + exitVal = (ssl3stats->hsh_sid_cache_misses != connections) || + (certsTested != connections); + + exitVal = ( exitVal || failed_already ); + SSL_ClearSessionCache(); + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + + PR_Cleanup(); + return exitVal; +} + diff --git a/security/nss/cmd/swfort/Makefile b/security/nss/cmd/swfort/Makefile new file mode 100644 index 000000000..a5b4350a6 --- /dev/null +++ b/security/nss/cmd/swfort/Makefile @@ -0,0 +1,108 @@ +#! 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. + +CORE_DEPTH = ../../.. + +include manifest.mn +include $(CORE_DEPTH)/coreconf/config.mk + +# $(NULL) + + +INCLUDES += \ + -I$(DIST)/../public/security \ + -I$(DIST)/../private/security \ + -I$(DEPTH)/security/lib/cert \ + -I$(DEPTH)/security/lib/key \ + -I$(DEPTH)/security/lib/util \ + -I./include \ + $(NULL) + + +# For the time being, sec stuff is export only +# US_FLAGS = -DEXPORT_VERSION -DUS_VERSION + +US_FLAGS = -DEXPORT_VERSION +EXPORT_FLAGS = -DEXPORT_VERSION + +BASE_LIBS = \ + $(DIST)/lib/libdbm.$(LIB_SUFFIX) \ + $(DIST)/lib/libxp.$(LIB_SUFFIX) \ + $(DIST)/lib/libnspr.$(LIB_SUFFIX) \ + $(NULL) + +# $(DIST)/lib/libpurenspr.$(LIB_SUFFIX) \ + +#There are a circular dependancies in security/lib, and we deal with it by +# double linking some libraries +SEC_LIBS = \ + $(DIST)/lib/libsecnav.$(LIB_SUFFIX) \ + $(DIST)/lib/libssl.$(LIB_SUFFIX) \ + $(DIST)/lib/libpkcs7.$(LIB_SUFFIX) \ + $(DIST)/lib/libcert.$(LIB_SUFFIX) \ + $(DIST)/lib/libkey.$(LIB_SUFFIX) \ + $(DIST)/lib/libsecmod.$(LIB_SUFFIX) \ + $(DIST)/lib/libcrypto.$(LIB_SUFFIX) \ + $(DIST)/lib/libsecutil.$(LIB_SUFFIX) \ + $(DIST)/lib/libssl.$(LIB_SUFFIX) \ + $(DIST)/lib/libpkcs7.$(LIB_SUFFIX) \ + $(DIST)/lib/libcert.$(LIB_SUFFIX) \ + $(DIST)/lib/libkey.$(LIB_SUFFIX) \ + $(DIST)/lib/libsecmod.$(LIB_SUFFIX) \ + $(DIST)/lib/libcrypto.$(LIB_SUFFIX) \ + $(DIST)/lib/libsecutil.$(LIB_SUFFIX) \ + $(DIST)/lib/libhash.$(LIB_SUFFIX) \ + $(NULL) + +MYLIB = lib/$(OBJDIR)/libsectool.$(LIB_SUFFIX) + +US_LIBS = $(MYLIB) $(SEC_LIBS) $(BASE_LIBS) $(MYLIB) $(BASE_LIBS) +EX_LIBS = $(MYLIB) $(SEC_LIBS) $(BASE_LIBS) $(MYLIB) $(BASE_LIBS) + +REQUIRES = libxp nspr security + +CSRCS = $(EXEC_SRCS) $(BI_SRCS) + +OBJS = $(CSRCS:.c=.o) $(BI_SRCS:.c=-us.o) $(BI_SRCS:.c=-ex.o) + +PROGS = $(addprefix $(OBJDIR)/, $(EXEC_SRCS:.c=$(BIN_SUFFIX))) +US_PROGS = $(addprefix $(OBJDIR)/, $(BI_SRCS:.c=-us$(BIN_SUFFIX))) +EX_PROGS = $(addprefix $(OBJDIR)/, $(BI_SRCS:.c=-ex$(BIN_SUFFIX))) + + +NON_DIRS = $(PROGS) $(US_PROGS) $(EX_PROGS) +TARGETS = $(NON_DIRS) + +include $(CORE_DEPTH)/coreconf/rules.mk + +symbols:: + @echo "TARGETS = $(TARGETS)" diff --git a/security/nss/cmd/swfort/instinit/Makefile b/security/nss/cmd/swfort/instinit/Makefile new file mode 100644 index 000000000..f912d54cd --- /dev/null +++ b/security/nss/cmd/swfort/instinit/Makefile @@ -0,0 +1,75 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../../platlibs.mk + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../../platrules.mk diff --git a/security/nss/cmd/swfort/instinit/instinit.c b/security/nss/cmd/swfort/instinit/instinit.c new file mode 100644 index 000000000..8b8b86c81 --- /dev/null +++ b/security/nss/cmd/swfort/instinit/instinit.c @@ -0,0 +1,421 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "prio.h" +#include "seccomon.h" +#include "swforti.h" +#include "cert.h" +#include "pk11func.h" +#include "nss.h" +#include "secutil.h" + +#define CERTDB_VALID_CA (1<<3) +#define CERTDB_TRUSTED_CA (1<<4) /* trusted for issuing server certs */ + +void secmod_GetInternalModule(SECMODModule *module); +void sec_SetCheckKRLState(int i); + +#define STEP 16 +void +printItem(SECItem *key) { + int i; + unsigned char *block; + int len; + for (block=key->data,len=key->len; len > 0; len -= STEP,block += STEP) { + for(i=0; i < STEP && i < len; i++) printf(" %02x ",block[i]); + printf("\n"); + } + printf("\n"); +} + +void +dump(unsigned char *block, int len) { + int i; + for (; len > 0; len -= STEP,block += STEP) { + for(i=0; i < STEP && i < len; i++) printf(" %02x ",block[i]); + printf("\n"); + } + printf("\n"); +} + + +/* + * We need to move this to security/cmd .. so we can use the password + * prompting infrastructure. + */ +char *GetUserInput(char * prompt) +{ + char phrase[200]; + + fprintf(stderr, "%s", prompt); + fflush (stderr); + + fgets ((char*) phrase, sizeof(phrase), stdin); + + /* stomp on newline */ + phrase[PORT_Strlen((char*)phrase)-1] = 0; + + /* Validate password */ + return (char*) PORT_Strdup((char*)phrase); +} + +void ClearPass(char *pass) { + PORT_Memset(pass,0,strlen(pass)); + PORT_Free(pass); +} + +char * +formatDERIssuer(FORTSWFile *file,SECItem *derIssuer) +{ + CERTName name; + SECStatus rv; + + PORT_Memset(&name,0,sizeof(name));; + rv = SEC_ASN1DecodeItem(file->arena,&name,CERT_NameTemplate,derIssuer); + if (rv != SECSuccess) { + return NULL; + } + return CERT_NameToAscii(&name); +} + +#define NETSCAPE_INIT_FILE "nsswft.swf" + +char *getDefaultTarget(void) +{ + char *fname = NULL; + char *home = NULL; + static char unix_home[512]; + + /* first try to get it from the environment */ + fname = getenv("SW_FORTEZZA_FILE"); + if (fname != NULL) { + return PORT_Strdup(fname); + } + +#ifdef XP_UNIX + home = getenv("HOME"); + if (home) { + strncpy(unix_home,home, sizeof(unix_home)-sizeof("/.netscape/"NETSCAPE_INIT_FILE)); + strcat(unix_home,"/.netscape/"NETSCAPE_INIT_FILE); + return unix_home; + } +#endif +#ifdef XP_WIN + home = getenv("windir"); + if (home) { + strncpy(unix_home,home, sizeof(unix_home)-sizeof("\\"NETSCAPE_INIT_FILE)); + strcat(unix_home,"\\"NETSCAPE_INIT_FILE); + return unix_home; + } +#endif + return (NETSCAPE_INIT_FILE); +} + +void +usage(char *prog) { + fprintf(stderr,"usage: %s [-v][-f][-t transport_pass][-u user_pass][-o output_file] source_file\n",prog); + exit(1); +} + +int main(int argc, char ** argv) +{ + + FORTSignedSWFile * swfile; + int size; + SECItem file; + char *progname = *argv++; + char *filename = NULL; + char *outname = NULL; + char *cp; + int verbose = 0; + int force = 0; + CERTCertDBHandle *certhandle = NULL; + CERTCertificate *cert; + CERTCertTrust *trust; + char * pass; + SECStatus rv; + int i; + int64 now; /* XXXX */ + char *issuer; + char *transport_pass = NULL; + char *user_pass = NULL; + SECItem *outItem = NULL; + PRFileDesc *fd; + PRFileInfo info; + PRStatus prv; + + + + + /* put better argument parsing here */ + while ((cp = *argv++) != NULL) { + if (*cp == '-') { + while (*++cp) { + switch (*cp) { + /* verbose mode */ + case 'v': + verbose++; + break; + /* explicitly set the target */ + case 'o': + outname = *argv++; + break; + case 'f': + /* skip errors in signatures without prompts */ + force++; + break; + case 't': + /* provide password on command line */ + transport_pass = *argv++; + break; + case 'u': + /* provide user password on command line */ + user_pass = *argv++; + break; + default: + usage(progname); + break; + } + } + } else if (filename) { + usage(progname); + } else { + filename = cp; + } + } + + if (filename == NULL) usage(progname); + if (outname == NULL) outname = getDefaultTarget(); + + + now = PR_Now(); + /* read the file in */ + fd = PR_Open(filename,PR_RDONLY,0); + if (fd == NULL) { + fprintf(stderr,"%s: couldn't open file \"%s\".\n",progname,filename); + exit(1); + } + + prv = PR_GetOpenFileInfo(fd,&info); + if (prv != PR_SUCCESS) { + fprintf(stderr,"%s: couldn't get info on file \"%s\".\n", + progname,filename); + exit(1); + } + + size = info.size; + + file.data = malloc(size); + file.len = size; + + file.len = PR_Read(fd,file.data,file.len); + if (file.len < 0) { + fprintf(stderr,"%s: couldn't read file \"%s\".\n",progname, filename); + exit(1); + } + + PR_Close(fd); + + /* Parse the file */ + swfile = FORT_GetSWFile(&file); + if (swfile == NULL) { + fprintf(stderr, + "%s: File \"%s\" not a valid FORTEZZA initialization file.\n", + progname,filename); + exit(1); + } + + issuer = formatDERIssuer(&swfile->file,&swfile->file.derIssuer); + if (issuer == NULL) { + issuer = "<Invalid Issuer DER>"; + } + + if (verbose) { + printf("Processing file %s ....\n",filename); + printf(" Version %ld\n",DER_GetInteger(&swfile->file.version)); + printf(" Issuer: %s\n",issuer); + printf(" Serial Number: "); + for (i=0; i < (int)swfile->file.serialID.len; i++) { + printf(" %02x",swfile->file.serialID.data[i]); + } + printf("\n"); + } + + + /* Check the Initalization phrase and save Kinit */ + if (!transport_pass) { + pass = SECU_GetPasswordString(NULL,"Enter the Initialization Memphrase:"); + transport_pass = pass; + } + rv = FORT_CheckInitPhrase(swfile,transport_pass); + if (rv != SECSuccess) { + fprintf(stderr, + "%s: Invalid Initialization Memphrase for file \"%s\".\n", + progname,filename); + exit(1); + } + + /* Check the user or init phrase and save Ks, use Kinit to unwrap the + * remaining data. */ + if (!user_pass) { + pass = SECU_GetPasswordString(NULL,"Enter the User Memphrase or the User PIN:"); + user_pass = pass; + } + rv = FORT_CheckUserPhrase(swfile,user_pass); + if (rv != SECSuccess) { + fprintf(stderr,"%s: Invalid User Memphrase or PIN for file \"%s\".\n", + progname,filename); + exit(1); + } + + NSS_NoDB_Init(NULL); + sec_SetCheckKRLState(1); + certhandle = CERT_GetDefaultCertDB(); + + /* now dump the certs into the temparary data base */ + for (i=0; swfile->file.slotEntries[i]; i++) { + int trusted = 0; + SECItem *derCert = FORT_GetDERCert(swfile, + swfile->file.slotEntries[i]->certIndex); + + if (derCert == NULL) { + if (verbose) { + printf(" Cert %02d: %s \"%s\" \n", + swfile->file.slotEntries[i]->certIndex, + "untrusted", "Couldn't decrypt Cert"); + } + continue; + } + cert = CERT_NewTempCertificate(certhandle, derCert, NULL, + PR_FALSE, PR_TRUE); + if (cert == NULL) { + if (verbose) { + printf(" Cert %02d: %s \"%s\" \n", + swfile->file.slotEntries[i]->certIndex, + "untrusted", "Couldn't decode Cert"); + } + continue; + } + if (swfile->file.slotEntries[i]->trusted.data[0]) { + /* Add TRUST */ + trust = PORT_ArenaAlloc(cert->arena,sizeof(CERTCertTrust)); + if (trust != NULL) { + trust->sslFlags = CERTDB_VALID_CA|CERTDB_TRUSTED_CA; + trust->emailFlags = CERTDB_VALID_CA|CERTDB_TRUSTED_CA; + trust->objectSigningFlags = CERTDB_VALID_CA|CERTDB_TRUSTED_CA; + cert->trust = trust; + trusted++; + } + } + if (verbose) { + printf(" Cert %02d: %s \"%s\" \n", + swfile->file.slotEntries[i]->certIndex, + trusted?" trusted ":"untrusted", + CERT_NameToAscii(&cert->subject)); + } + } + + fflush(stdout); + + + cert = CERT_FindCertByName(certhandle,&swfile->file.derIssuer); + if (cert == NULL) { + fprintf(stderr,"%s: Couldn't find signer certificate \"%s\".\n", + progname,issuer); + rv = SECFailure; + goto noverify; + } + rv = CERT_VerifySignedData(&swfile->signatureWrap,cert, now, NULL); + if (rv != SECSuccess) { + fprintf(stderr, + "%s: Couldn't verify the signature on file \"%s\" with certificate \"%s\".\n", + progname,filename,issuer); + goto noverify; + } + rv = CERT_VerifyCert(certhandle, cert, PR_TRUE, certUsageSSLServer, + now ,NULL,NULL); + /* not an normal cert, see if it's a CA? */ + if (rv != SECSuccess) { + rv = CERT_VerifyCert(certhandle, cert, PR_TRUE, certUsageAnyCA, + now ,NULL,NULL); + } + if (rv != SECSuccess) { + fprintf(stderr,"%s: Couldn't verify the signer certificate \"%s\".\n", + progname,issuer); + goto noverify; + } + +noverify: + if (rv != SECSuccess) { + if (!force) { + pass = GetUserInput( + "Signature verify failed, continue without verification? "); + if (!(pass && ((*pass == 'Y') || (*pass == 'y')))) { + exit(1); + } + } + } + + + /* now write out the modified init file for future use */ + outItem = FORT_PutSWFile(swfile); + if (outItem == NULL) { + fprintf(stderr,"%s: Couldn't format target init file.\n", + progname); + goto noverify; + } + + if (verbose) { + printf("writing modified file out to \"%s\".\n",outname); + } + + /* now write it out */ + fd = PR_Open(outname,PR_WRONLY|PR_CREATE_FILE|PR_TRUNCATE,0700); + if (fd == NULL) { + fprintf(stderr,"%s: couldn't open file \"%s\".\n",progname,outname); + exit(1); + } + + file.len = PR_Write(fd,outItem->data,outItem->len); + if (file.len < 0) { + fprintf(stderr,"%s: couldn't read file \"%s\".\n",progname, filename); + exit(1); + } + + PR_Close(fd); + + exit(0); + return (0); +} + diff --git a/security/nss/cmd/swfort/instinit/manifest.mn b/security/nss/cmd/swfort/instinit/manifest.mn new file mode 100644 index 000000000..8380f4246 --- /dev/null +++ b/security/nss/cmd/swfort/instinit/manifest.mn @@ -0,0 +1,46 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../../.. + +DEFINES += -DNSPR20 + +MODULE = nss + +CSRCS = instinit.c + +REQUIRES = nspr dbm seccmd + +PROGRAM = instinit +# PROGRAM = ./$(OBJDIR)/selfserv.exe + +USE_STATIC_LIBS = 1 diff --git a/security/nss/cmd/swfort/manifest.mn b/security/nss/cmd/swfort/manifest.mn new file mode 100644 index 000000000..aaacd83e8 --- /dev/null +++ b/security/nss/cmd/swfort/manifest.mn @@ -0,0 +1,38 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +REQUIRES = nss seccmd dbm + + +DIRS = instinit newuser diff --git a/security/nss/cmd/swfort/newuser/Makefile b/security/nss/cmd/swfort/newuser/Makefile new file mode 100644 index 000000000..f0a47a0a3 --- /dev/null +++ b/security/nss/cmd/swfort/newuser/Makefile @@ -0,0 +1,83 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +ctmp := $(shell $(MAKE) -C ../../../lib/fortcrypt --no-print-directory cilib_name) +ifeq ($(ctmp), $(patsubst /%,/,$(ctmp))) + CILIB := ../../../lib/fortcrypt/$(ctmp) +else + CILIB := $(ctmp) +endif + +EXTRA_LIBS += $(CILIB) + +include ../../platlibs.mk + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +include ../../platrules.mk + diff --git a/security/nss/cmd/swfort/newuser/manifest.mn b/security/nss/cmd/swfort/newuser/manifest.mn new file mode 100644 index 000000000..4554c69ef --- /dev/null +++ b/security/nss/cmd/swfort/newuser/manifest.mn @@ -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. +# +CORE_DEPTH = ../../../.. + +DEFINES += -DNSPR20 + +MODULE = nss + +CSRCS = newuser.c mktst.c + +REQUIRES = nspr dbm seccmd + +PROGRAM = newuser + +USE_STATIC_LIBS = 1 diff --git a/security/nss/cmd/swfort/newuser/mktst.c b/security/nss/cmd/swfort/newuser/mktst.c new file mode 100644 index 000000000..6e111d3dd --- /dev/null +++ b/security/nss/cmd/swfort/newuser/mktst.c @@ -0,0 +1,254 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "prio.h" +#include "swforti.h" +#include "maci.h" +#include "secder.h" +#include "blapi.h" + +void +printkey(char *s, unsigned char *block) { + int i; + printf("%s \n 0x",s); + for(i=0; i < 10; i++) printf("%02x",block[i]); + printf("\n"); +} + +void +printblock(char *s, unsigned char *block) { + int i; + printf("%s \n 0x",s); + for(i=0; i < 8; i++) printf("%02x",block[i]); + printf("\n 0x"); + for(i=8; i < 16; i++) printf("%02x",block[i]); + printf("\n"); +} + + +static char *leafbits="THIS IS NOT LEAF"; + +static void +encryptCertEntry(fortProtectedData *pdata,FORTSkipjackKeyPtr Ks, + unsigned char *data,int len) +{ + unsigned char *dataout; + int enc_len; + /* XXX Make length */ + pdata->dataIV.data = PORT_ZAlloc(24); + pdata->dataIV.len = 24; + PORT_Memcpy(pdata->dataIV.data,leafbits,SKIPJACK_LEAF_SIZE); + fort_GenerateRandom(&pdata->dataIV.data[SKIPJACK_LEAF_SIZE], + SKIPJACK_BLOCK_SIZE); + enc_len = (len + (SKIPJACK_BLOCK_SIZE-1)) & ~(SKIPJACK_BLOCK_SIZE-1); + dataout = pdata->dataEncryptedWithKs.data = PORT_ZAlloc(enc_len); + pdata->dataEncryptedWithKs.len = enc_len; + fort_skipjackEncrypt(Ks,&pdata->dataIV.data[SKIPJACK_LEAF_SIZE], + enc_len, data,dataout); + if (len > 255) { + pdata->length.data = PORT_ZAlloc(2); + pdata->length.data[0] = (len >> 8) & 0xff; + pdata->length.data[1] = len & 0xff; + pdata->length.len = 2; + } else { + pdata->length.data = PORT_ZAlloc(1); + pdata->length.data[0] = len & 0xff; + pdata->length.len = 1; + } + +} + +unsigned char issuer[30] = { 0 }; + +void +makeCertSlot(fortSlotEntry *entry,int index,char *label,SECItem *cert, + FORTSkipjackKeyPtr Ks, unsigned char *xKEA, unsigned char *xDSA, + unsigned char *pubKey, int pubKeyLen, unsigned char *p, unsigned char *q, + unsigned char *g) +{ + unsigned char *key; /* private key */ + + entry->trusted.data = PORT_Alloc(1); + *entry->trusted.data = index == 0 ? 1 : 0; + entry->trusted.len = 1; + entry->certificateIndex.data = PORT_Alloc(1); + *entry->certificateIndex.data = index; + entry->certificateIndex.len = 1; + entry->certIndex = index; + encryptCertEntry(&entry->certificateLabel,Ks, + (unsigned char *)label, strlen(label)); + encryptCertEntry(&entry->certificateData,Ks, cert->data, cert->len); + if (xKEA) { + entry->exchangeKeyInformation = PORT_ZNew(fortKeyInformation); + entry->exchangeKeyInformation->keyFlags.data = PORT_ZAlloc(1); + entry->exchangeKeyInformation->keyFlags.data[0] = 1; + entry->exchangeKeyInformation->keyFlags.len = 1; + key = PORT_Alloc(24); + fort_skipjackWrap(Ks,24,xKEA,key); + entry->exchangeKeyInformation->privateKeyWrappedWithKs.data = key; + entry->exchangeKeyInformation->privateKeyWrappedWithKs.len = 24; + entry->exchangeKeyInformation->derPublicKey.data = pubKey; + entry->exchangeKeyInformation->derPublicKey.len = pubKeyLen; + entry->exchangeKeyInformation->p.data = p; + entry->exchangeKeyInformation->p.len = 128; + entry->exchangeKeyInformation->q.data = q; + entry->exchangeKeyInformation->q.len = 20; + entry->exchangeKeyInformation->g.data = g; + entry->exchangeKeyInformation->g.len = 128; + + entry->signatureKeyInformation = PORT_ZNew(fortKeyInformation); + entry->signatureKeyInformation->keyFlags.data = PORT_ZAlloc(1); + entry->signatureKeyInformation->keyFlags.data[0] = 1; + entry->signatureKeyInformation->keyFlags.len = 1; + key = PORT_Alloc(24); + fort_skipjackWrap(Ks,24,xDSA,key); + entry->signatureKeyInformation->privateKeyWrappedWithKs.data = key; + entry->signatureKeyInformation->privateKeyWrappedWithKs.len = 24; + entry->signatureKeyInformation->derPublicKey.data = pubKey; + entry->signatureKeyInformation->derPublicKey.len = pubKeyLen; + entry->signatureKeyInformation->p.data = p; + entry->signatureKeyInformation->p.len = 128; + entry->signatureKeyInformation->q.data = q; + entry->signatureKeyInformation->q.len = 20; + entry->signatureKeyInformation->g.data = g; + entry->signatureKeyInformation->g.len = 128; + } else { + entry->exchangeKeyInformation = NULL; + entry->signatureKeyInformation = NULL; + } + + return; +} + + +void +makeProtectedPhrase(FORTSWFile *file, fortProtectedPhrase *prot_phrase, + FORTSkipjackKeyPtr Ks, FORTSkipjackKeyPtr Kinit, char *phrase) +{ + SHA1Context *sha; + unsigned char hashout[SHA1_LENGTH]; + FORTSkipjackKey Kfek; + unsigned int len; + unsigned char cw[4]; + unsigned char enc_version[2]; + unsigned char *data = NULL; + int keySize; + int i,version; + char tmp_data[13]; + + if (strlen(phrase) < 12) { + PORT_Memset(tmp_data, ' ', sizeof(tmp_data)); + PORT_Memcpy(tmp_data,phrase,strlen(phrase)); + tmp_data[12] = 0; + phrase = tmp_data; + } + + /* now calculate the PBE key for fortezza */ + sha = SHA1_NewContext(); + SHA1_Begin(sha); + version = DER_GetUInteger(&file->version); + enc_version[0] = (version >> 8) & 0xff; + enc_version[1] = version & 0xff; + SHA1_Update(sha,enc_version,sizeof(enc_version)); + SHA1_Update(sha,file->derIssuer.data, file->derIssuer.len); + SHA1_Update(sha,file->serialID.data, file->serialID.len); + SHA1_Update(sha,(unsigned char *)phrase,strlen(phrase)); + SHA1_End(sha,hashout,&len,SHA1_LENGTH); + PORT_Memcpy(Kfek,hashout,sizeof(FORTSkipjackKey)); + + keySize = sizeof(CI_KEY); + if (Kinit) keySize = SKIPJACK_BLOCK_SIZE*2; + data = PORT_ZAlloc(keySize); + prot_phrase->wrappedKValue.data = data; + prot_phrase->wrappedKValue.len = keySize; + fort_skipjackWrap(Kfek,sizeof(CI_KEY),Ks,data); + + /* first, decrypt the hashed/Encrypted Memphrase */ + data = (unsigned char *) PORT_ZAlloc(SHA1_LENGTH+sizeof(cw)); + + /* now build the hash for comparisons */ + SHA1_Begin(sha); + SHA1_Update(sha,(unsigned char *)phrase,strlen(phrase)); + SHA1_End(sha,hashout,&len,SHA1_LENGTH); + SHA1_DestroyContext(sha,PR_TRUE); + + + /* now calcuate the checkword and compare it */ + cw[0] = cw[1] = cw[2] = cw[3] = 0; + for (i=0; i <5 ; i++) { + cw[0] = cw[0] ^ hashout[i*4]; + cw[1] = cw[1] ^ hashout[i*4+1]; + cw[2] = cw[2] ^ hashout[i*4+2]; + cw[3] = cw[3] ^ hashout[i*4+3]; + } + + PORT_Memcpy(data,hashout,len); + PORT_Memcpy(data+len,cw,sizeof(cw)); + + prot_phrase->memPhraseIV.data = PORT_ZAlloc(24); + prot_phrase->memPhraseIV.len = 24; + PORT_Memcpy(prot_phrase->memPhraseIV.data,leafbits,SKIPJACK_LEAF_SIZE); + fort_GenerateRandom(&prot_phrase->memPhraseIV.data[SKIPJACK_LEAF_SIZE], + SKIPJACK_BLOCK_SIZE); + prot_phrase->kValueIV.data = PORT_ZAlloc(24); + prot_phrase->kValueIV.len = 24; + PORT_Memcpy(prot_phrase->kValueIV.data,leafbits,SKIPJACK_LEAF_SIZE); + fort_GenerateRandom(&prot_phrase->kValueIV.data[SKIPJACK_LEAF_SIZE], + SKIPJACK_BLOCK_SIZE); + fort_skipjackEncrypt(Ks,&prot_phrase->memPhraseIV.data[SKIPJACK_LEAF_SIZE], + len+sizeof(cw), data,data); + + prot_phrase->hashedEncryptedMemPhrase.data = data; + prot_phrase->hashedEncryptedMemPhrase.len = len+sizeof(cw); + + if (Kinit) { + fort_skipjackEncrypt(Kinit, + &prot_phrase->kValueIV.data[SKIPJACK_LEAF_SIZE], + prot_phrase->wrappedKValue.len, + prot_phrase->wrappedKValue.data, + prot_phrase->wrappedKValue.data ); + } + + return; +} + + +void +fill_in(SECItem *item,unsigned char *data, int len) +{ + item->data = PORT_Alloc(len); + PORT_Memcpy(item->data,data,len); + item->len = len; +} + diff --git a/security/nss/cmd/swfort/newuser/newuser.c b/security/nss/cmd/swfort/newuser/newuser.c new file mode 100644 index 000000000..33b6b853a --- /dev/null +++ b/security/nss/cmd/swfort/newuser/newuser.c @@ -0,0 +1,1133 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 <fcntl.h> +#include <sys/types.h> +#ifdef XP_UNIX +#include <unistd.h> +#endif +#include "cryptint.h" +#include "blapi.h" /* program calls low level functions directly!*/ +#include "pk11func.h" +#include "secmod.h" +/*#include "secmodi.h"*/ +#include "cert.h" +#include "key.h" +#include "nss.h" +#include "swforti.h" +#include "secutil.h" +#include "secrng.h" + +#ifndef O_BINARY +#define O_BINARY 0 +#endif + +#define MAX_PERSONALITIES 50 +typedef struct { + int index; + CI_CERT_STR label; + CERTCertificate *cert; +} certlist; + +typedef struct { + int card; + int index; + CI_CERT_STR label; + certlist valid[MAX_PERSONALITIES]; + int count; +} Cert; + + +#define EMAIL_OID_LEN 9 +#define EMAIL_OID 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x09, 0x01 +unsigned char emailAVA[127] = { + 0x31, 6+EMAIL_OID_LEN, /* Set */ + 0x30, 4+EMAIL_OID_LEN, /* Sequence */ + 0x06, EMAIL_OID_LEN, EMAIL_OID, + 0x13, 0, /* printable String */ +}; +#define EMAIL_DATA_START 8+EMAIL_OID_LEN + +int emailOffset[] = { 1, 3, EMAIL_DATA_START-1 }; +int offsetCount = sizeof(emailOffset)/sizeof(emailOffset[0]); + +unsigned char hash[20] = { 'H', 'a', 's', 'h', ' ', 'F', 'a', 'i', 'l', 'e', + 'd', ' ', '*', '*', '*', '*', '*', '*', '*', '*' }; +unsigned char sig[40] = { 'H', 'a', 's', 'h', ' ', 'F', 'a', 'i', 'l', 'e', + 'd', ' ', '*', '*', '*', '*', '*', '*', '*', '*', + '>', '>', '>', ' ', 'N', 'o', 't', ' ', 'S', 'i', + 'g', 'n', 'd', ' ', '<', '<', '<', ' ', ' ', ' ' }; + + +/*void *malloc(int); */ + +unsigned char *data_start(unsigned char *buf, int length, int *data_length) +{ + unsigned char tag; + int used_length= 0; + + tag = buf[used_length++]; + + /* blow out when we come to the end */ + if (tag == 0) { + return NULL; + } + + *data_length = buf[used_length++]; + + if (*data_length&0x80) { + int len_count = *data_length & 0x7f; + + *data_length = 0; + + while (len_count-- > 0) { + *data_length = (*data_length << 8) | buf[used_length++]; + } + } + + if (*data_length > (length-used_length) ) { + *data_length = length-used_length; + return NULL; + } + + return (buf + used_length); +} + +unsigned char * +GetAbove(unsigned char *cert,int cert_length,int *above_len) +{ + unsigned char *buf = cert; + int buf_length = cert_length; + unsigned char *tmp; + int len; + + *above_len = 0; + + /* optional serial number */ + if ((buf[0] & 0xa0) == 0xa0) { + tmp = data_start(buf,buf_length,&len); + if (tmp == NULL) return NULL; + buf_length -= (tmp-buf) + len; + buf = tmp + len; + } + /* serial number */ + tmp = data_start(buf,buf_length,&len); + if (tmp == NULL) return NULL; + buf_length -= (tmp-buf) + len; + buf = tmp + len; + /* skip the OID */ + tmp = data_start(buf,buf_length,&len); + if (tmp == NULL) return NULL; + buf_length -= (tmp-buf) + len; + buf = tmp + len; + /* issuer */ + tmp = data_start(buf,buf_length,&len); + if (tmp == NULL) return NULL; + buf_length -= (tmp-buf) + len; + buf = tmp + len; + /* skip the date */ + tmp = data_start(buf,buf_length,&len); + if (tmp == NULL) return NULL; + buf_length -= (tmp-buf) + len; + buf = tmp + len; + + *above_len = buf - cert; + return cert; +} + +unsigned char * +GetSubject(unsigned char *cert,int cert_length,int *subj_len) { + unsigned char *buf = cert; + int buf_length = cert_length; + unsigned char *tmp; + int len; + + *subj_len = 0; + + /* optional serial number */ + if ((buf[0] & 0xa0) == 0xa0) { + tmp = data_start(buf,buf_length,&len); + if (tmp == NULL) return NULL; + buf_length -= (tmp-buf) + len; + buf = tmp + len; + } + /* serial number */ + tmp = data_start(buf,buf_length,&len); + if (tmp == NULL) return NULL; + buf_length -= (tmp-buf) + len; + buf = tmp + len; + /* skip the OID */ + tmp = data_start(buf,buf_length,&len); + if (tmp == NULL) return NULL; + buf_length -= (tmp-buf) + len; + buf = tmp + len; + /* issuer */ + tmp = data_start(buf,buf_length,&len); + if (tmp == NULL) return NULL; + buf_length -= (tmp-buf) + len; + buf = tmp + len; + /* skip the date */ + tmp = data_start(buf,buf_length,&len); + if (tmp == NULL) return NULL; + buf_length -= (tmp-buf) + len; + buf = tmp + len; + + return data_start(buf,buf_length,subj_len); +} + +unsigned char * +GetBelow(unsigned char *cert,int cert_length,int *below_len) { + unsigned char *subj; + int subj_len; + unsigned char *below; + + *below_len = 0; + + subj = GetSubject(cert,cert_length,&subj_len); + + below = subj + subj_len; + *below_len = cert_length - (below - cert); + return below; +} + +unsigned char * +GetSignature(unsigned char *sig,int sig_length,int *subj_len) { + unsigned char *buf = sig; + int buf_length = sig_length; + unsigned char *tmp; + int len; + + *subj_len = 0; + + /* signature oid */ + tmp = data_start(buf,buf_length,&len); + if (tmp == NULL) return NULL; + buf_length -= (tmp-buf) + len; + buf = tmp + len; + /* signature data */ + tmp = data_start(buf,buf_length,&len); + if (tmp == NULL) return NULL; + + *subj_len = len -1; + return tmp+1; +} + +int DER_Sequence(unsigned char *buf, int length) { + int next = 0; + + buf[next++] = 0x30; + if (length < 0x80) { + buf[next++] = length; + } else { + buf[next++] = 0x82; + buf[next++] = (length >> 8) & 0xff; + buf[next++] = length & 0xff; + } + return next; +} + +static +int Cert_length(unsigned char *buf, int length) { + unsigned char tag; + int used_length= 0; + int data_length; + + tag = buf[used_length++]; + + /* blow out when we come to the end */ + if (tag == 0) { + return 0; + } + + data_length = buf[used_length++]; + + if (data_length&0x80) { + int len_count = data_length & 0x7f; + + data_length = 0; + + while (len_count-- > 0) { + data_length = (data_length << 8) | buf[used_length++]; + } + } + + if (data_length > (length-used_length) ) { + return length; + } + + return (data_length + used_length); +} + +int +InitCard(int card, char *inpass) { + int cirv; + char buf[50]; + char *pass; + + cirv = CI_Open( 0 /* flags */, card); + if (cirv != CI_OK) return cirv; + + if (inpass == NULL) { + sprintf(buf,"Enter PIN for card in socket %d: ",card); + pass = SECU_GetPasswordString(NULL, buf); + + if (pass == NULL) { + CI_Close(CI_POWER_DOWN_FLAG,card); + return CI_FAIL; + } + } else pass=inpass; + + cirv = CI_CheckPIN(CI_USER_PIN,(unsigned char *)pass); + if (cirv != CI_OK) { + CI_Close(CI_POWER_DOWN_FLAG,card); + } + return cirv; +} + +int +isUser(CI_PERSON *person) { + return 1; +} + +int +isCA(CI_PERSON *person) { + return 0; +} + +int FoundCert(int card, char *name, Cert *cert) { + CI_PERSON personalities[MAX_PERSONALITIES]; + CI_PERSON *person; + int cirv; + int i; + int user_len = strlen(name); + + PORT_Memset(personalities, 0, sizeof(CI_PERSON)*MAX_PERSONALITIES); + + cirv = CI_GetPersonalityList(MAX_PERSONALITIES,personalities); + if (cirv != CI_OK) return 0; + + + cert->count = 1; + cert->valid[0].index = 0; + memcpy(cert->valid[0].label,"RRXX0000Root PAA Certificate ", + sizeof(cert->valid[0].label)); + cert->valid[0].cert = NULL; + for (i=0; i < MAX_PERSONALITIES; i++) { + person = &personalities[i]; + if ( (PORT_Memcmp(person->CertLabel,"RRXX",4) == 0) || + (PORT_Memcmp(person->CertLabel,"RTXX",4) == 0) || + (PORT_Memcmp(person->CertLabel,"LAXX",4) == 0) || + (PORT_Memcmp(person->CertLabel,"INKS",4) == 0) || + (PORT_Memcmp(person->CertLabel,"INKX",4) == 0) || + (PORT_Memcmp(person->CertLabel,"ONKS",4) == 0) || + (PORT_Memcmp(person->CertLabel,"ONKX",4) == 0) || + (PORT_Memcmp(person->CertLabel,"KEAK",4) == 0) || + (PORT_Memcmp(person->CertLabel,"3IKX",4) == 0) || + (PORT_Memcmp(person->CertLabel,"DSA1",4) == 0) || + (PORT_Memcmp(person->CertLabel,"DSAI",4) == 0) || + (PORT_Memcmp(person->CertLabel,"DSAO",4) == 0) || + (PORT_Memcmp(person->CertLabel,"3IXS",4) == 0) || + (PORT_Memcmp(person->CertLabel,"3OXS",4) == 0) ){ + int index; + + cert->valid[cert->count].cert = NULL; + memcpy(cert->valid[cert->count].label, + person->CertLabel,sizeof(person->CertLabel)); + for (index = sizeof(person->CertLabel)-1; + cert->valid[cert->count].label[index] == ' '; index--) { + cert->valid[cert->count].label[index] = 0; + } + cert->valid[cert->count++].index = person->CertificateIndex; + } + } + for (i=0; i < MAX_PERSONALITIES; i++) { + person = &personalities[i]; + if (strncmp((char *)&person->CertLabel[8],name,user_len) == 0) { + cert->card = card; + cert->index = person->CertificateIndex; + memcpy(&cert->label,person->CertLabel,sizeof(person->CertLabel)); + return 1; + } + } + return 0; +} + +void +Terminate(char *mess, int cirv, int card1, int card2) +{ + fprintf(stderr,"FAIL: %s error %d\n",mess,cirv); + if (card1 != -1) CI_Close(CI_POWER_DOWN_FLAG,card1); + if (card2 != -1) CI_Close(CI_POWER_DOWN_FLAG,card2); + CI_Terminate(); + exit(1); +} + +void +usage(char *prog) +{ + fprintf(stderr,"usage: %s [-e email][-t transport][-u userpin][-U userpass][-s ssopin][-S ssopass][-o outfile] common_name ca_label\n",prog); + exit(1); +} + +#define CERT_SIZE 2048 + + +/* version and oid */ +unsigned char header[] = { + /* Cert OID */ + 0x02, 0x10, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, + 0x30, 0x0b, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x01, 0x13 }; + +#define KEY_START 21 +#define KMID_OFFSET 4 +#define KEA_OFFSET 15 +#define DSA_OFFSET 148 +unsigned char key[] = { + /* Sequence(Constructed): 293 bytes (0x125) */ + 0x30, 0x82, 0x01, 0x25, + /*Sequence(Constructed): 11 bytes (0xb) */ + 0x30, 0x0b, + /* ObjectId(Universal): 9 bytes (0x9) */ + 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x01, 0x14, + /* BitString(Universal): 276 bytes (0x114) */ + 0x03, 0x82, 0x01, 0x14, + 0x00, 0x00, 0x01, 0xef, 0x04, 0x01, 0x00, 0x01, + 0x00, 0x00, 0x69, 0x60, 0x70, 0x00, 0x80, 0x02, + 0x2e, 0x46, 0xb9, 0xcb, 0x22, 0x72, 0x0b, 0x1c, + 0xe6, 0x25, 0x20, 0x16, 0x86, 0x05, 0x8e, 0x2b, + 0x98, 0xd1, 0x46, 0x3d, 0x00, 0xb8, 0x69, 0xe1, + 0x1a, 0x42, 0x7d, 0x7d, 0xb5, 0xbf, 0x9f, 0x26, + 0xd3, 0x2c, 0xb1, 0x73, 0x01, 0xb6, 0xb2, 0x6f, + 0x7b, 0xa5, 0x54, 0x85, 0x60, 0x77, 0x81, 0x8a, + 0x87, 0x86, 0xe0, 0x2d, 0xbf, 0xdb, 0x28, 0xe8, + 0xfa, 0x20, 0x35, 0xb4, 0xc0, 0x94, 0x10, 0x8e, + 0x1c, 0x58, 0xaa, 0x02, 0x60, 0x97, 0xf5, 0xb3, + 0x2f, 0xf8, 0x99, 0x29, 0x28, 0x73, 0x47, 0x36, + 0xdd, 0x1d, 0x78, 0x95, 0xeb, 0xb8, 0xec, 0x45, + 0x96, 0x69, 0x6f, 0x54, 0xc8, 0x1f, 0x2d, 0x3a, + 0xd9, 0x0e, 0x8e, 0xaa, 0x59, 0x11, 0x8c, 0x3b, + 0x8d, 0xa4, 0xed, 0xf2, 0x7d, 0xdc, 0x42, 0xaa, + 0xa4, 0xd2, 0x1c, 0xb9, 0x87, 0xd0, 0xd9, 0x3d, + 0x8e, 0x89, 0xbb, 0x06, 0x54, 0xcf, 0x32, 0x00, + 0x02, 0x00, 0x00, 0x80, 0x0b, 0x80, 0x6c, 0x0f, + 0x71, 0xd1, 0xa1, 0xa9, 0x26, 0xb4, 0xf1, 0xcd, + 0x6a, 0x7a, 0x09, 0xaa, 0x58, 0x28, 0xd7, 0x35, + 0x74, 0x8e, 0x7c, 0x83, 0xcb, 0xfe, 0x00, 0x3b, + 0x62, 0x00, 0xfb, 0x90, 0x37, 0xcd, 0x93, 0xcf, + 0xf3, 0xe4, 0x6d, 0x8d, 0xdd, 0xb8, 0x53, 0xe0, + 0x5c, 0xda, 0x1a, 0x7e, 0x56, 0x03, 0x95, 0x03, + 0x2f, 0x74, 0x86, 0xb1, 0xa0, 0xbb, 0x05, 0x91, + 0xe4, 0x76, 0x83, 0xe6, 0x62, 0xf9, 0x12, 0x64, + 0x5a, 0x62, 0xd8, 0x94, 0x04, 0x1f, 0x83, 0x02, + 0x2e, 0xc5, 0xa7, 0x17, 0x46, 0x46, 0x21, 0x96, + 0xc3, 0xa9, 0x8e, 0x92, 0x18, 0xd1, 0x52, 0x08, + 0x1d, 0xff, 0x8e, 0x24, 0xdb, 0x6c, 0xd8, 0xfe, + 0x80, 0x93, 0xe1, 0xa5, 0x4a, 0x0a, 0x37, 0x24, + 0x18, 0x07, 0xbe, 0x0f, 0xaf, 0x73, 0xea, 0x50, + 0x64, 0xa1, 0xb3, 0x77, 0xe5, 0x41, 0x02, 0x82, + 0x39, 0xb9, 0xe3, 0x94 +}; + +unsigned char valitity[] = { + 0x30, 0x1e, + 0x17, 0x0d, + '2','0','0','0','0','1','0','1','0','0','0','0','Z', + 0x17, 0x0d, + '2','0','0','5','1','2','0','1','0','0','0','0','Z' +}; + + +unsigned char cnam_oid[] = { 0x06, 0x03, 0x55, 0x04, 0x03 }; + +unsigned char signature[] = { + /* the OID */ + 0x30, 0x0b, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x01, 0x13, + /* signature wrap */ + 0x03, 0x29, 0x00, + /* 40 byte dsa signature */ + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff +}; + +unsigned char fortezza_oid [] = { + 0x60, 0x86, 0x48, 0x01, 0x65, 0x02, 0x01, 0x01, 0x13 +}; + +unsigned char software_ou[] = { + 0x31, 26, 0x30, 24, + 0x06, 0x03, 0x55, 0x04, 0x0b, + 0x13, 17, + 'S','o','f','t','w', + 'a','r','e',' ','F', + 'O','R','T','E','Z','Z','A' +}; + + +char letterarray[] = { + 'a','b','c','d','e','f','g','h','i','j','k','l','m','n', + 'o','p','q','r','s','t','u','v','w','x','y','z' }; + +char constarray[] = { + 'b','c','d','f','g','h','j','k','l','m','n', + 'p','q','r','s','t','v','w','x','y','z' }; + +char vowelarray[] = { + 'a','e','i','o','u','y' }; + +char digitarray[] = { + '0','1','2','3','4','5','6','7','8','9' }; + +unsigned long +getRandom(unsigned long max) { + unsigned short data; + unsigned long result; + + fort_GenerateRandom((unsigned char *)&data,sizeof(data)); + + result = (unsigned long)data * max; + result = result >> 16; + return result; +} + + +char getLetter(void) +{ + return letterarray[getRandom(sizeof(letterarray))]; +} +char getVowel(void) +{ + return vowelarray[getRandom(sizeof(vowelarray))]; +} +char getDigit(void) +{ + return digitarray[getRandom(sizeof(digitarray))]; +} + +char getConst(void) +{ + return constarray[getRandom(sizeof(constarray))]; +} + +char *getPinPhrase(void) +{ + char * pass = PORT_ZAlloc(5); + + pass[0] = getDigit(); + pass[1] = getDigit(); + pass[2] = getDigit(); + pass[3] = getDigit(); + + return pass; +} + +char *getPassPhrase(void) +{ + char * pass = PORT_ZAlloc(13); + + pass[0] = getConst()+'A'-'a'; + pass[1] = getVowel(); + pass[2] = getConst(); + pass[3] = getVowel(); + pass[4] = getConst(); + pass[5] = getVowel(); + pass[6] = getConst(); + pass[7] = getDigit(); + pass[8] = getDigit(); + pass[9] = getDigit(); + pass[10] = getDigit(); + pass[11] = getLetter()+'A'-'a'; + + return pass; +} + +extern void +makeCertSlot(fortSlotEntry * entry, + int index, + char * label, + SECItem * cert, + FORTSkipjackKeyPtr Ks, + unsigned char *xKEA, + unsigned char *xDSA, + unsigned char *pubKey, + int pubKeyLen, + unsigned char *p, + unsigned char *q, + unsigned char *g); + +extern void +makeProtectedPhrase(FORTSWFile * file, + fortProtectedPhrase *prot_phrase, + FORTSkipjackKeyPtr Ks, + FORTSkipjackKeyPtr Kinit, + char * phrase); + +extern void +fill_in(SECItem *item, unsigned char *data, int len); + +char *userLabel = "INKS0002 "; +int main(int argc, char **argv) +{ + char *progname = *argv++; + char *commonName = NULL; + char *caname = NULL; + char *email = NULL; + char *outname = NULL; + char *cp; + int arg_count = 0; + Cert caCert; + SECItem userCert; + int cirv,i; + int cards, start; + unsigned char *subject; + int subject_len; + int signature_len = sizeof(signature); + int newSubject_len, newCertBody_len, len; + int cname1_len, cname_len, pstring_len; + int valitity_len = sizeof(valitity); + unsigned char origCert[CERT_SIZE]; + unsigned char newSubject[CERT_SIZE]; + unsigned char newCertBody[CERT_SIZE]; + unsigned char newCert[CERT_SIZE]; + unsigned char pstring[CERT_SIZE]; + unsigned char cname1[CERT_SIZE]; + unsigned char cname[CERT_SIZE]; + CERTCertificate *myCACert = NULL; + CERTCertificate *cert; + CERTCertDBHandle *certhandle; + SECStatus rv; + unsigned char serial[16]; + SECKEYPublicKey *pubKey; + DSAPrivateKey *keaPrivKey; + DSAPrivateKey *dsaPrivKey; + CI_RANDOM randomVal; + PQGParams *params; + int pca_index = -1; + unsigned char *p,*q,*g; + FORTSkipjackKey Ks; + FORTSkipjackKey Kinit; + FORTSWFile *file; + FORTSignedSWFile *signed_file; + FORTSignedSWFile *signed_file2; + unsigned char random[20]; + unsigned char vers; + unsigned char *data; + char *transportPin=NULL; + char *ssoMemPhrase=NULL; + char *userMemPhrase=NULL; + char *ssoPin=NULL; + char *userPin=NULL; + char *pass=NULL; + SECItem *outItem; + int email_len = 0; + int emailAVA_len = 0; + + + /* put better argument parsing here */ + while ((cp = *argv++) != NULL) { + if (*cp == '-') { + while (*++cp) { + switch (*cp) { + /* verbose mode */ + case 'e': + email = *argv++; + break; + /* explicitly set the target */ + case 'o': + outname = *argv++; + break; + case 't': + /* provide password on command line */ + transportPin = *argv++; + break; + case 'u': + /* provide user password on command line */ + userPin = *argv++; + break; + case 'U': + /* provide user password on command line */ + userMemPhrase = *argv++; + break; + case 's': + /* provide user password on command line */ + ssoPin = *argv++; + break; + case 'S': + /* provide user password on command line */ + ssoMemPhrase = *argv++; + break; + case 'p': + /* provide card password on command line */ + pass = *argv++; + break; + case 'd': + transportPin="test1234567890"; + ssoMemPhrase="sso1234567890"; + userMemPhrase="user1234567890"; + ssoPin="9999"; + userPin="0000"; + break; + default: + usage(progname); + break; + } + } + } else switch (arg_count++) { + case 0: + commonName = cp; + break; + case 1: + caname = cp; + break; + default: + usage(progname); + } + } + + if (outname == NULL) outname = "swfort.sfi"; + if (caname == NULL) usage(progname); + + + + caCert.card = -1; + memset(newCert,0,CERT_SIZE); + + if (commonName == NULL) usage(progname); + + + cirv = CI_Initialize(&cards); + + start = 0; + for (i=0; i < cards; i++) { + cirv = InitCard(i+1,pass); + if (cirv == CI_OK) { + if (FoundCert(i+1,caname,&caCert)) { + break; + } + } + } + + if (caCert.card == -1) { + fprintf(stderr, + "WARNING: Couldn't find Signing CA...new cert will not be signed\n"); + } + + + /* + * initialize enough security to deal with certificates. + */ + NSS_NoDB_Init(NULL); + certhandle = CERT_GetDefaultCertDB(); + if (certhandle == NULL) { + Terminate("Couldn't build temparary Cert Database", + 1, -1, caCert.card); + exit(1); + } + + CI_GenerateRandom(random); + RNG_RandomUpdate(random,sizeof(random)); + CI_GenerateRandom(random); + RNG_RandomUpdate(random,sizeof(random)); + + + if (transportPin == NULL) transportPin = getPassPhrase(); + if (ssoMemPhrase == NULL) ssoMemPhrase = getPassPhrase(); + if (userMemPhrase == NULL) userMemPhrase = getPassPhrase(); + if (ssoPin == NULL) ssoPin = getPinPhrase(); + if (userPin == NULL) userPin = getPinPhrase(); + + + + /* now dump the certs into the temparary data base */ + for (i=0; i < caCert.count; i++) { + int trusted = 0; + SECItem derCert; + + cirv = CI_Select(caCert.card); + if (cirv != CI_OK) { + Terminate("Couldn't select on CA card",cirv, + -1, caCert.card); + } + cirv = CI_GetCertificate(caCert.valid[i].index,origCert); + if (cirv != CI_OK) { + continue; + } + derCert.data = origCert; + derCert.len = Cert_length(origCert, sizeof(origCert)); + cert = + (CERTCertificate *)CERT_NewTempCertificate(certhandle,&derCert, NULL, + PR_FALSE, PR_TRUE); + caCert.valid[i].cert = cert; + if (cert == NULL) continue; + if (caCert.valid[i].index == caCert.index) myCACert=cert; + if (caCert.valid[i].index == atoi((char *)&caCert.label[4])) + pca_index = i; + } + + if (myCACert == NULL) { + Terminate("Couldn't find CA's Certificate", 1, -1, caCert.card); + exit(1); + } + + + /* + * OK now build the user cert. + */ + /* first get the serial number and KMID */ + cirv = CI_GenerateRandom(randomVal); + memcpy(&header[2],randomVal,sizeof(serial)); + memcpy(serial,randomVal,sizeof(serial)); + memcpy(&key[KEY_START+KMID_OFFSET],randomVal+sizeof(serial),7); + /* KMID */ + + /* now generate the keys */ + pubKey = CERT_ExtractPublicKey(myCACert); + if (pubKey == NULL) { + Terminate("Couldn't extract CA's public key", + 1, -1, caCert.card); + exit(1); + } + + + switch (pubKey->keyType) { + case fortezzaKey: + params = (PQGParams *)&pubKey->u.fortezza.params; + break; + case dsaKey: + params = (PQGParams *)&pubKey->u.dsa.params; + break; + default: + Terminate("Certificate is not a fortezza or DSA Cert", + 1, -1, caCert.card); + exit(1); + } + + rv = DSA_NewKey(params,&keaPrivKey); + if (rv != SECSuccess) { + Terminate("Couldn't Generate KEA key", + PORT_GetError(), -1, caCert.card); + exit(1); + } + rv = DSA_NewKey(params,&dsaPrivKey); + if (rv != SECSuccess) { + Terminate("Couldn't Generate DSA key", + PORT_GetError(), -1, caCert.card); + exit(1); + } + + if (keaPrivKey->publicValue.len == 129) + keaPrivKey->publicValue.data++; + if (dsaPrivKey->publicValue.len == 129) + dsaPrivKey->publicValue.data++; + if (keaPrivKey->privateValue.len == 21) + keaPrivKey->privateValue.data++; + if (dsaPrivKey->privateValue.len == 21) + dsaPrivKey->privateValue.data++; + + /* save the parameters */ + p = params->prime.data; + if (params->prime.len == 129) p++; + q = params->subPrime.data; + if (params->subPrime.len == 21) q++; + g = params->base.data; + if (params->base.len == 129) g++; + + memcpy(&key[KEY_START+KEA_OFFSET], + keaPrivKey->publicValue.data, + keaPrivKey->publicValue.len); + memcpy(&key[KEY_START+DSA_OFFSET], + dsaPrivKey->publicValue.data, + dsaPrivKey->publicValue.len); + + /* build the der subject */ + subject = data_start(myCACert->derSubject.data,myCACert->derSubject.len, + &subject_len); + + /* build the new Common name AVA */ + len = DER_Sequence(pstring,strlen(commonName)); + memcpy(pstring+len,commonName,strlen(commonName)); + len += strlen(commonName); + pstring_len = len; + pstring[0] = 0x13; + + len = DER_Sequence(cname1,sizeof(cnam_oid)+pstring_len); + memcpy(cname1+len,cnam_oid,sizeof(cnam_oid)); len += sizeof(cnam_oid); + memcpy(cname1+len,pstring,pstring_len); len += pstring_len; + cname1_len = len; + + len = DER_Sequence(cname, cname1_len); + memcpy(cname+len,cname1,cname1_len); len += cname1_len; + cname_len = len; + cname[0] = 0x31; /* make it a set rather than a sequence */ + + if (email) { + email_len = strlen(email); + emailAVA_len = EMAIL_DATA_START + email_len; + } + + /* now assemble it */ + len = DER_Sequence(newSubject,subject_len + sizeof(software_ou) + + cname_len + emailAVA_len); + memcpy(newSubject+len,subject,subject_len); + + for (i=0; i < subject_len; i++) { + if (memcmp(newSubject+len+i,cnam_oid,sizeof(cnam_oid)) == 0) { + newSubject[i+len+4] = 0x0b; /* change CN to OU */ + break; + } + } + len += subject_len; + memcpy(newSubject+len,software_ou,sizeof(software_ou)); + len += sizeof(software_ou); + memcpy(newSubject+len,cname,cname_len); len += cname_len; + newSubject_len = len; + + /* + * build the email AVA + */ + if (email) { + memcpy(&emailAVA[EMAIL_DATA_START],email,email_len); + for (i=0; i < offsetCount; i++) { + emailAVA[emailOffset[i]] += email_len; + } + memcpy(newSubject+len,emailAVA,emailAVA_len); + newSubject_len += emailAVA_len; + } + + + /* + * Assemble the Cert + */ + + len = DER_Sequence(newCertBody,sizeof(header)+newSubject_len+ + valitity_len+myCACert->derSubject.len+sizeof(key)); + memcpy(newCertBody+len,header,sizeof(header));len += sizeof(header); + memcpy(newCertBody+len,myCACert->derSubject.data, + myCACert->derSubject.len);len += myCACert->derSubject.len; + memcpy(newCertBody+len,valitity,valitity_len);len += valitity_len; + memcpy(newCertBody+len,newSubject,newSubject_len); + len += newSubject_len; + memcpy(newCertBody+len,key,sizeof(key));len += sizeof(key); + newCertBody_len = len; + + + /* + * generate the hash + */ + cirv = CI_InitializeHash(); + if (cirv == CI_OK) { + int hash_left = newCertBody_len & 63; + int hash_len = newCertBody_len - hash_left; + cirv = CI_Hash(hash_len,newCertBody); + if (cirv == CI_OK) { + cirv = CI_GetHash(hash_left,newCertBody+hash_len,hash); + } + } + + /* + * now sign the hash + */ + if ((cirv == CI_OK) && (caCert.card != -1)) { + cirv = CI_Select(caCert.card); + if (cirv == CI_OK) { + cirv = CI_SetPersonality(caCert.index); + if (cirv == CI_OK) { + cirv = CI_Sign(hash,sig); + } + } + } else cirv = -1; + + if (cirv != CI_OK) { + memcpy(sig,hash,sizeof(hash)); + } + + /* + * load in new signature + */ + { + int sig_len; + unsigned char *sig_start = + GetSignature(signature,signature_len,&sig_len); + memcpy(sig_start,sig,sizeof(sig)); + } + + /* + * now do the final wrap + */ + len = DER_Sequence(newCert,newCertBody_len+signature_len); + memcpy(newCert+len,newCertBody,newCertBody_len); len += newCertBody_len; + memcpy(newCert+len, signature, signature_len); len +=signature_len; + userCert.data = newCert; + userCert.len = len; + + + /* OK, we now have our cert, let's go build our software file */ + signed_file = PORT_ZNew(FORTSignedSWFile); + file = &signed_file->file; + + signed_file->signatureWrap.signature.data = PORT_ZAlloc(40); + signed_file->signatureWrap.signature.len = 40; + signed_file->signatureWrap.signatureAlgorithm.algorithm.data = + fortezza_oid; + signed_file->signatureWrap.signatureAlgorithm.algorithm.len = + sizeof(fortezza_oid); + + vers = 1; + fill_in(&file->version,&vers,1); + file->derIssuer.data = myCACert->derSubject.data; + file->derIssuer.len = myCACert->derSubject.len; + file->serialID.data = serial; + file->serialID.len =sizeof(serial); + /* generate out Ks value */ + fort_GenerateRandom(Ks,sizeof(Ks)); + makeProtectedPhrase(file,&file->initMemPhrase,Kinit,NULL,transportPin); + makeProtectedPhrase(file,&file->ssoMemPhrase,Ks,Kinit,ssoMemPhrase); + makeProtectedPhrase(file,&file->ssoPinPhrase,Ks,Kinit,ssoPin); + makeProtectedPhrase(file,&file->userMemPhrase,Ks,Kinit,userMemPhrase); + makeProtectedPhrase(file,&file->userPinPhrase,Ks,Kinit,userPin); + file->wrappedRandomSeed.data = PORT_ZAlloc(12); + file->wrappedRandomSeed.len = 12; + cirv = fort_GenerateRandom(file->wrappedRandomSeed.data,10); + if (cirv != CI_OK) { + Terminate("Couldn't get Random Seed", + cirv, -1, caCert.card); + } + fort_skipjackWrap(Ks,12,file->wrappedRandomSeed.data, + file->wrappedRandomSeed.data); + file->slotEntries = PORT_ZAlloc(sizeof(fortSlotEntry *)*5); + /* paa */ + file->slotEntries[0] = PORT_ZNew(fortSlotEntry); + makeCertSlot(file->slotEntries[0],0, + (char *)caCert.valid[0].label, + &caCert.valid[0].cert->derCert, + Ks,NULL,NULL,NULL,0,p,q,g); + /* pca */ + file->slotEntries[1] = PORT_ZNew(fortSlotEntry); + makeCertSlot(file->slotEntries[1],1, + (char *)caCert.valid[pca_index].label, + &caCert.valid[pca_index].cert->derCert, + Ks,NULL,NULL,NULL,0,p,q,g); + /* ca */ + file->slotEntries[2] = PORT_ZNew(fortSlotEntry); + /* make sure the caCert lable points to our new pca slot location */ + caCert.label[4] = '0'; + caCert.label[5] = '0'; + caCert.label[6] = '0'; + caCert.label[7] = '1'; + makeCertSlot(file->slotEntries[2],2,(char *)caCert.label, + &myCACert->derCert,Ks,NULL,NULL,NULL,0,p,q,g); + /* user */ + file->slotEntries[3] = PORT_ZNew(fortSlotEntry); + strncpy(&userLabel[8],commonName,sizeof(CI_PERSON)-8); + makeCertSlot(file->slotEntries[3],3,userLabel,&userCert,Ks, + keaPrivKey->privateValue.data, + dsaPrivKey->privateValue.data, + key, sizeof(key), p, q, g); + file->slotEntries[4] = 0; + + /* encode the file so we can sign it */ + outItem = FORT_PutSWFile(signed_file); + + /* get the der encoded data to sign */ + signed_file2 = FORT_GetSWFile(outItem); + + /* now sign it */ + len = signed_file2->signatureWrap.data.len; + data = signed_file2->signatureWrap.data.data; + /* + * generate the hash + */ + cirv = CI_InitializeHash(); + if (cirv == CI_OK) { + int hash_left = len & 63; + int hash_len = len - hash_left; + cirv = CI_Hash(hash_len,data); + if (cirv == CI_OK) { + cirv = CI_GetHash(hash_left,data+hash_len,hash); + } + } + + /* + * now sign the hash + */ + if ((cirv == CI_OK) && (caCert.card != -1)) { + cirv = CI_Select(caCert.card); + if (cirv == CI_OK) { + cirv = CI_SetPersonality(caCert.index); + if (cirv == CI_OK) { + cirv = CI_Sign(hash,sig); + } + } + } else cirv = -1; + + if (cirv != CI_OK) { + memcpy(sig,hash,sizeof(hash)); + } + memcpy( signed_file->signatureWrap.signature.data,sig,sizeof(sig)); + signed_file->signatureWrap.signature.len = sizeof(sig)*8; + + + /* encode it for the last time */ + outItem = FORT_PutSWFile(signed_file); + + + /* + * write it out to the .sfi file + */ + { + int fd = open(outname,O_WRONLY|O_CREAT|O_BINARY,0777); + + write(fd,outItem->data,outItem->len); + close(fd); + } + CI_Close(CI_POWER_DOWN_FLAG,caCert.card); + CI_Terminate(); + + printf("Wrote %s to file %s.\n",commonName,outname); + printf("Initialization Memphrase: %s\n",transportPin); + printf("SSO Memphrase: %s\n",ssoMemPhrase); + printf("User Memphrase: %s\n",userMemPhrase); + printf("SSO pin: %s\n",ssoPin); + printf("User pin: %s\n",userPin); + + return 0; +} + diff --git a/security/nss/cmd/tests/Makefile b/security/nss/cmd/tests/Makefile new file mode 100644 index 000000000..da66e20df --- /dev/null +++ b/security/nss/cmd/tests/Makefile @@ -0,0 +1,73 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk diff --git a/security/nss/cmd/tests/manifest.mn b/security/nss/cmd/tests/manifest.mn new file mode 100644 index 000000000..878effc3c --- /dev/null +++ b/security/nss/cmd/tests/manifest.mn @@ -0,0 +1,49 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +CSRCS = remtest.c + +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = seccmd dbm + +PROGRAMS = $(CSRCS:.c=) + +TARGETS = $(PROGRAMS) + +#NO_MD_RELEASE = 1 diff --git a/security/nss/cmd/tests/remtest.c b/security/nss/cmd/tests/remtest.c new file mode 100644 index 000000000..b17bc0f8b --- /dev/null +++ b/security/nss/cmd/tests/remtest.c @@ -0,0 +1,162 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/* +** +** Sample client side test program that uses SSL and libsec +** +*/ + +#include "secutil.h" + +#if defined(XP_UNIX) +#include <unistd.h> +#else +#include "ctype.h" /* for isalpha() */ +#endif + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> + +#include "nspr.h" +#include "prio.h" +#include "prnetdb.h" +#include "nss.h" +#include "pk11func.h" +#include "plgetopt.h" + +void +Usage(char *progName) +{ + fprintf(stderr,"usage: %s [-d profiledir] -t tokenName [-r]\n", progName); + exit(1); +} + +int main(int argc, char **argv) +{ + char * certDir = NULL; + PLOptState *optstate; + PLOptStatus optstatus; + SECStatus rv; + char * tokenName = NULL; + PRBool cont=PR_TRUE; + PK11TokenEvent event = PK11TokenPresentEvent; + PK11TokenStatus status; + char *progName; + PK11SlotInfo *slot; + + progName = strrchr(argv[0], '/'); + if (!progName) + progName = strrchr(argv[0], '\\'); + progName = progName ? progName+1 : argv[0]; + + optstate = PL_CreateOptState(argc, argv, "rd:t:"); + while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + + case 'd': + certDir = strdup(optstate->value); + certDir = SECU_ConfigDirectory(certDir); + break; + case 't': + tokenName = strdup(optstate->value); + break; + case 'r': + event = PK11TokenRemovedOrChangedEvent; + break; + } + } + if (optstatus == PL_OPT_BAD) + Usage(progName); + + if (tokenName == NULL) { + Usage(progName); + } + + if (!certDir) { + certDir = SECU_DefaultSSLDir(); /* Look in $SSL_DIR */ + certDir = SECU_ConfigDirectory(certDir); /* call even if it's NULL */ + } + + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + + PK11_SetPasswordFunc(SECU_GetModulePassword); + + /* open the cert DB, the key DB, and the secmod DB. */ + rv = NSS_Init(certDir); + if (rv != SECSuccess) { + SECU_PrintError(progName, "unable to open cert database"); + return 1; + } + + printf("Looking up tokenNamed: <%s>\n",tokenName); + slot = PK11_FindSlotByName(tokenName); + if (slot == NULL) { + SECU_PrintError(progName, "unable to find token"); + return 1; + } + + do { + status = + PK11_WaitForTokenEvent(slot,event,PR_INTERVAL_NO_TIMEOUT, 0, 0); + + switch (status) { + case PK11TokenNotRemovable: + cont = PR_FALSE; + printf("%s Token Not Removable\n",tokenName); + break; + case PK11TokenChanged: + event = PK11TokenRemovedOrChangedEvent; + printf("%s Token Changed\n", tokenName); + break; + case PK11TokenRemoved: + event = PK11TokenPresentEvent; + printf("%s Token Removed\n", tokenName); + break; + case PK11TokenPresent: + event = PK11TokenRemovedOrChangedEvent; + printf("%s Token Present\n", tokenName); + break; + } + } while (cont); + + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + PR_Cleanup(); + return 0; +} diff --git a/security/nss/cmd/tstclnt/Makefile b/security/nss/cmd/tstclnt/Makefile new file mode 100644 index 000000000..b31a4fdc8 --- /dev/null +++ b/security/nss/cmd/tstclnt/Makefile @@ -0,0 +1,84 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +ifeq (,$(filter-out WINNT WIN95 WIN16,$(OS_TARGET))) # omits WINCE +ifndef BUILD_OPT +ifndef NS_USE_GCC +LDFLAGS += /subsystem:console /profile /debug /machine:I386 /incremental:no +endif +OS_CFLAGS += -D_CONSOLE +endif +endif + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + +#include ../platlibs.mk + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +include ../platrules.mk + diff --git a/security/nss/cmd/tstclnt/makefile.win b/security/nss/cmd/tstclnt/makefile.win new file mode 100644 index 000000000..6cf6c12cf --- /dev/null +++ b/security/nss/cmd/tstclnt/makefile.win @@ -0,0 +1,130 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +VERBOSE = 1 +include <manifest.mn> + +#cannot define PROGRAM in manifest compatibly with NT and UNIX +PROGRAM = tstclnt +PROGRAM = ./$(OBJDIR)/$(PROGRAM).exe +include <$(DEPTH)\config\config.mak> + +# let manifest generate C_OBJS, it will prepend ./$(OBJDIR)/ +# rules.mak will append C_OBJS onto OBJS. +# OBJS = $(CSRCS:.c=.obj) + +# include files are looked for in $LINCS and $INCS. +# $LINCS is in manifest.mnw, computed from REQUIRES= +INCS = $(INCS) \ + -I$(DEPTH)/security/lib/cert \ + -I../include \ + $(NULL) + +IGNORE_ME = \ + -I$(DEPTH)/security/lib/key \ + -I$(DEPTH)/security/lib/util \ + $(NULL) + + +WINFE = $(DEPTH)/cmd/winfe/mkfiles$(MOZ_BITS)/x86Dbg + +# these files are the content of libdbm +DBM_LIB = \ + $(WINFE)/DB.obj \ + $(WINFE)/HASH.obj \ + $(WINFE)/H_BIGKEY.obj \ + $(WINFE)/H_PAGE.obj \ + $(WINFE)/H_LOG2.obj \ + $(WINFE)/H_FUNC.obj \ + $(WINFE)/HASH_BUF.obj \ + $(NULL) + +MOZ_LIBS = \ + $(WINFE)/ALLXPSTR.obj \ + $(WINFE)/XP_ERROR.obj \ + $(WINFE)/XPASSERT.obj \ + $(WINFE)/XP_REG.obj \ + $(WINFE)/XP_TRACE.obj \ + $(DBM_LIB) \ + $(WINFE)/XP_STR.obj \ + $(WINFE)/MKTEMP.obj \ + $(NULL) + +SEC_LIBS = \ + $(DIST)/lib/cert$(MOZ_BITS).lib \ + $(DIST)/lib/crypto$(MOZ_BITS).lib \ + $(DIST)/lib/hash$(MOZ_BITS).lib \ + $(DIST)/lib/key$(MOZ_BITS).lib \ + $(DIST)/lib/pkcs7$(MOZ_BITS).lib \ + $(DIST)/lib/secmod$(MOZ_BITS).lib \ + $(DIST)/lib/secutl$(MOZ_BITS).lib \ + $(DIST)/lib/ssl$(MOZ_BITS).lib \ + $(NULL) + +LLFLAGS = $(LLFLAGS) \ + ../lib/$(OBJDIR)/sectool$(MOZ_BITS).lib \ + $(SEC_LIBS) \ + $(MOZ_LIBS) \ + $(DEPTH)/nspr/src/$(OBJDIR)/getopt.obj \ + $(LIBNSPR) \ + $(NULL) + + +include <$(DEPTH)\config\rules.mak> + +INSTALL = $(MAKE_INSTALL) + +objs: $(OBJS) + +$(PROGRAM):: + $(INSTALL) $(DIST)/bin/pr3240.dll ./$(OBJDIR) + +programs: $(PROGRAM) + +install:: $(TARGETS) + $(INSTALL) $(TARGETS) $(DIST)/bin + + +symbols: + @echo "CSRCS = $(CSRCS)" + @echo "INCS = $(INCS)" + @echo "OBJS = $(OBJS)" + @echo "LIBRARY = $(LIBRARY)" + @echo "PROGRAM = $(PROGRAM)" + @echo "TARGETS = $(TARGETS)" + @echo "DIST = $(DIST)" + @echo "VERSION_NUMBER = $(VERSION_NUMBER)" + @echo "WINFE = $(WINFE)" + @echo "DBM_LIB = $(DBM_LIB)" + @echo "INSTALL = $(INSTALL)" + diff --git a/security/nss/cmd/tstclnt/manifest.mn b/security/nss/cmd/tstclnt/manifest.mn new file mode 100644 index 000000000..8762227e4 --- /dev/null +++ b/security/nss/cmd/tstclnt/manifest.mn @@ -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. +# + +CORE_DEPTH = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +# This next line is used by .mk files +# and gets translated into $LINCS in manifest.mnw +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = seccmd dbm + +# DIRS = + +CSRCS = tstclnt.c + +PROGRAM = tstclnt + diff --git a/security/nss/cmd/tstclnt/tstclnt.c b/security/nss/cmd/tstclnt/tstclnt.c new file mode 100644 index 000000000..84f08f3a6 --- /dev/null +++ b/security/nss/cmd/tstclnt/tstclnt.c @@ -0,0 +1,779 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Dr Vipul Gupta <vipul.gupta@sun.com>, Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the + * terms of 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. + */ + +/* +** +** Sample client side test program that uses SSL and libsec +** +*/ + +#include "secutil.h" + +#if defined(XP_UNIX) +#include <unistd.h> +#else +#include "ctype.h" /* for isalpha() */ +#endif + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> + +#include "nspr.h" +#include "prio.h" +#include "prnetdb.h" +#include "nss.h" +#include "ssl.h" +#include "sslproto.h" +#include "pk11func.h" +#include "plgetopt.h" + +#define PRINTF if (verbose) printf +#define FPRINTF if (verbose) fprintf + +#define MAX_WAIT_FOR_SERVER 600 +#define WAIT_INTERVAL 100 + +int ssl2CipherSuites[] = { + SSL_EN_RC4_128_WITH_MD5, /* A */ + SSL_EN_RC4_128_EXPORT40_WITH_MD5, /* B */ + SSL_EN_RC2_128_CBC_WITH_MD5, /* C */ + SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */ + SSL_EN_DES_64_CBC_WITH_MD5, /* E */ + SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* F */ +#ifdef NSS_ENABLE_ECC + /* NOTE: Since no new SSL2 ciphersuites are being + * invented, and we've run out of lowercase letters + * for SSL3 ciphers, we use letters G and beyond + * for new SSL3 ciphers. + */ + TLS_ECDH_ECDSA_WITH_NULL_SHA, /* G */ + TLS_ECDH_ECDSA_WITH_RC4_128_SHA, /* H */ + TLS_ECDH_ECDSA_WITH_DES_CBC_SHA, /* I */ + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, /* J */ + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, /* K */ + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, /* L */ + TLS_ECDH_RSA_WITH_NULL_SHA, /* M */ + TLS_ECDH_RSA_WITH_RC4_128_SHA, /* N */ + TLS_ECDH_RSA_WITH_DES_CBC_SHA, /* O */ + TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, /* P */ + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, /* Q */ + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, /* R */ + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* S */ + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* T */ +#endif /* NSS_ENABLE_ECC */ + 0 +}; + +int ssl3CipherSuites[] = { + SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, /* a */ + SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, /* b */ + SSL_RSA_WITH_RC4_128_MD5, /* c */ + SSL_RSA_WITH_3DES_EDE_CBC_SHA, /* d */ + SSL_RSA_WITH_DES_CBC_SHA, /* e */ + SSL_RSA_EXPORT_WITH_RC4_40_MD5, /* f */ + SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* g */ + SSL_FORTEZZA_DMS_WITH_NULL_SHA, /* h */ + SSL_RSA_WITH_NULL_MD5, /* i */ + SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, /* j */ + SSL_RSA_FIPS_WITH_DES_CBC_SHA, /* k */ + TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, /* l */ + TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, /* m */ + SSL_RSA_WITH_RC4_128_SHA, /* n */ + TLS_DHE_DSS_WITH_RC4_128_SHA, /* o */ + SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, /* p */ + SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, /* q */ + SSL_DHE_RSA_WITH_DES_CBC_SHA, /* r */ + SSL_DHE_DSS_WITH_DES_CBC_SHA, /* s */ + TLS_DHE_DSS_WITH_AES_128_CBC_SHA, /* t */ + TLS_DHE_RSA_WITH_AES_128_CBC_SHA, /* u */ + TLS_RSA_WITH_AES_128_CBC_SHA, /* v */ + TLS_DHE_DSS_WITH_AES_256_CBC_SHA, /* w */ + TLS_DHE_RSA_WITH_AES_256_CBC_SHA, /* x */ + TLS_RSA_WITH_AES_256_CBC_SHA, /* y */ + SSL_RSA_WITH_NULL_SHA, /* z */ + 0 +}; + +unsigned long __cmp_umuls; +PRBool verbose; + +static char *progName; + +/* This exists only for the automated test suite. It allows us to + * pass in a password on the command line. + */ + +char *password = NULL; + +char * ownPasswd( PK11SlotInfo *slot, PRBool retry, void *arg) +{ + char *passwd = NULL; + if ( (!retry) && arg ) { + passwd = PL_strdup((char *)arg); + } + return passwd; +} + +void printSecurityInfo(PRFileDesc *fd) +{ + CERTCertificate * cert; + SSL3Statistics * ssl3stats = SSL_GetStatistics(); + SECStatus result; + SSLChannelInfo channel; + SSLCipherSuiteInfo suite; + + result = SSL_GetChannelInfo(fd, &channel, sizeof channel); + if (result == SECSuccess && + channel.length == sizeof channel && + channel.cipherSuite) { + result = SSL_GetCipherSuiteInfo(channel.cipherSuite, + &suite, sizeof suite); + if (result == SECSuccess) { + FPRINTF(stderr, + "tstclnt: SSL version %d.%d using %d-bit %s with %d-bit %s MAC\n", + channel.protocolVersion >> 8, channel.protocolVersion & 0xff, + suite.effectiveKeyBits, suite.symCipherName, + suite.macBits, suite.macAlgorithmName); + FPRINTF(stderr, + "tstclnt: Server Auth: %d-bit %s, Key Exchange: %d-bit %s\n", + channel.authKeyBits, suite.authAlgorithmName, + channel.keaKeyBits, suite.keaTypeName); + } + } + cert = SSL_RevealCert(fd); + if (cert) { + char * ip = CERT_NameToAscii(&cert->issuer); + char * sp = CERT_NameToAscii(&cert->subject); + if (sp) { + fprintf(stderr, "subject DN: %s\n", sp); + PR_Free(sp); + } + if (ip) { + fprintf(stderr, "issuer DN: %s\n", ip); + PR_Free(ip); + } + CERT_DestroyCertificate(cert); + cert = NULL; + } + fprintf(stderr, + "%ld cache hits; %ld cache misses, %ld cache not reusable\n", + ssl3stats->hsh_sid_cache_hits, ssl3stats->hsh_sid_cache_misses, + ssl3stats->hsh_sid_cache_not_ok); + +} + +void +handshakeCallback(PRFileDesc *fd, void *client_data) +{ + printSecurityInfo(fd); +} + +static void Usage(const char *progName) +{ + printf( +"Usage: %s -h host [-p port] [-d certdir] [-n nickname] [-23Tovx] \n" +" [-c ciphers] [-w passwd] [-q]\n", progName); + printf("%-20s Hostname to connect with\n", "-h host"); + printf("%-20s Port number for SSL server\n", "-p port"); + printf("%-20s Directory with cert database (default is ~/.netscape)\n", + "-d certdir"); + printf("%-20s Nickname of key and cert for client auth\n", "-n nickname"); + printf("%-20s Disable SSL v2.\n", "-2"); + printf("%-20s Disable SSL v3.\n", "-3"); + printf("%-20s Disable TLS (SSL v3.1).\n", "-T"); + printf("%-20s Override bad server cert. Make it OK.\n", "-o"); + printf("%-20s Verbose progress reporting.\n", "-v"); + printf("%-20s Use export policy.\n", "-x"); + printf("%-20s Ping the server and then exit.\n", "-q"); + printf("%-20s Letter(s) chosen from the following list\n", "-c ciphers"); + printf( +"A SSL2 RC4 128 WITH MD5\n" +"B SSL2 RC4 128 EXPORT40 WITH MD5\n" +"C SSL2 RC2 128 CBC WITH MD5\n" +"D SSL2 RC2 128 CBC EXPORT40 WITH MD5\n" +"E SSL2 DES 64 CBC WITH MD5\n" +"F SSL2 DES 192 EDE3 CBC WITH MD5\n" +#ifdef NSS_ENABLE_ECC +"G TLS ECDH ECDSA WITH NULL SHA\n" +"H TLS ECDH ECDSA WITH RC4 128 CBC SHA\n" +"I TLS ECDH ECDSA WITH DES CBC SHA\n" +"J TLS ECDH ECDSA WITH 3DES EDE CBC SHA\n" +"K TLS ECDH ECDSA WITH AES 128 CBC SHA\n" +"L TLS ECDH ECDSA WITH AES 256 CBC SHA\n" +"M TLS ECDH RSA WITH NULL SHA\n" +"N TLS ECDH RSA WITH RC4 128 CBC SHA\n" +"O TLS ECDH RSA WITH DES CBC SHA\n" +"P TLS ECDH RSA WITH 3DES EDE CBC SHA\n" +"Q TLS ECDH RSA WITH AES 128 CBC SHA\n" +"R TLS ECDH RSA WITH AES 256 CBC SHA\n" +"S TLS ECDHE ECDSA WITH AES 128 CBC SHA\n" +"T TLS ECDHE RSA WITH AES 128 CBC SHA\n" +#endif /* NSS_ENABLE_ECC */ +"\n" +"a SSL3 FORTEZZA DMS WITH FORTEZZA CBC SHA\n" +"b SSL3 FORTEZZA DMS WITH RC4 128 SHA\n" +"c SSL3 RSA WITH RC4 128 MD5\n" +"d SSL3 RSA WITH 3DES EDE CBC SHA\n" +"e SSL3 RSA WITH DES CBC SHA\n" +"f SSL3 RSA EXPORT WITH RC4 40 MD5\n" +"g SSL3 RSA EXPORT WITH RC2 CBC 40 MD5\n" +"h SSL3 FORTEZZA DMS WITH NULL SHA\n" +"i SSL3 RSA WITH NULL MD5\n" +"j SSL3 RSA FIPS WITH 3DES EDE CBC SHA\n" +"k SSL3 RSA FIPS WITH DES CBC SHA\n" +"l SSL3 RSA EXPORT WITH DES CBC SHA\t(new)\n" +"m SSL3 RSA EXPORT WITH RC4 56 SHA\t(new)\n" +"n SSL3 RSA WITH RC4 128 SHA\n" +"o SSL3 DHE DSS WITH RC4 128 SHA\n" +"p SSL3 DHE RSA WITH 3DES EDE CBC SHA\n" +"q SSL3 DHE DSS WITH 3DES EDE CBC SHA\n" +"r SSL3 DHE RSA WITH DES CBC SHA\n" +"s SSL3 DHE DSS WITH DES CBC SHA\n" +"t SSL3 DHE DSS WITH AES 128 CBC SHA\n" +"u SSL3 DHE RSA WITH AES 128 CBC SHA\n" +"v SSL3 RSA WITH AES 128 CBC SHA\n" +"w SSL3 DHE DSS WITH AES 256 CBC SHA\n" +"x SSL3 DHE RSA WITH AES 256 CBC SHA\n" +"y SSL3 RSA WITH AES 256 CBC SHA\n" +"z SSL3 RSA WITH NULL SHA\n" + ); + exit(1); +} + +void +milliPause(PRUint32 milli) +{ + PRIntervalTime ticks = PR_MillisecondsToInterval(milli); + PR_Sleep(ticks); +} + +void +disableAllSSLCiphers(void) +{ + const PRUint16 *cipherSuites = SSL_ImplementedCiphers; + int i = SSL_NumImplementedCiphers; + SECStatus rv; + + /* disable all the SSL3 cipher suites */ + while (--i >= 0) { + PRUint16 suite = cipherSuites[i]; + rv = SSL_CipherPrefSetDefault(suite, PR_FALSE); + if (rv != SECSuccess) { + PRErrorCode err = PR_GetError(); + printf("SSL_CipherPrefSet didn't like value 0x%04x (i = %d): %s\n", + suite, i, SECU_Strerror(err)); + exit(2); + } + } +} + +/* + * Callback is called when incoming certificate is not valid. + * Returns SECSuccess to accept the cert anyway, SECFailure to reject. + */ +static SECStatus +ownBadCertHandler(void * arg, PRFileDesc * socket) +{ + PRErrorCode err = PR_GetError(); + /* can log invalid cert here */ + printf("Bad server certificate: %d, %s\n", err, SECU_Strerror(err)); + return SECSuccess; /* override, say it's OK. */ +} + +int main(int argc, char **argv) +{ + PRFileDesc * s; + PRFileDesc * std_out; + CERTCertDBHandle * handle; + char * host = NULL; + char * port = "443"; + char * certDir = NULL; + char * nickname = NULL; + char * cipherString = NULL; + int multiplier = 0; + SECStatus rv; + PRStatus status; + PRInt32 filesReady; + PRInt32 ip; + int npds; + int override = 0; + int disableSSL2 = 0; + int disableSSL3 = 0; + int disableTLS = 0; + int useExportPolicy = 0; + int file_read = 0; + PRSocketOptionData opt; + PRNetAddr addr; + PRHostEnt hp; + PRPollDesc pollset[2]; + char buf[PR_NETDB_BUF_SIZE]; + PRBool useCommandLinePassword = PR_FALSE; + PRBool pingServerFirst = PR_FALSE; + int error=0; + PLOptState *optstate; + PLOptStatus optstatus; + PRStatus prStatus; + + progName = strrchr(argv[0], '/'); + if (!progName) + progName = strrchr(argv[0], '\\'); + progName = progName ? progName+1 : argv[0]; + + optstate = PL_CreateOptState(argc, argv, "23Tfc:h:p:d:m:n:oqvw:x"); + while ((optstatus = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch (optstate->option) { + case '?': + default : Usage(progName); break; + + case '2': disableSSL2 = 1; break; + + case '3': disableSSL3 = 1; break; + + case 'T': disableTLS = 1; break; + + case 'c': cipherString = strdup(optstate->value); break; + + case 'h': host = strdup(optstate->value); break; +#ifdef _WINDOWS + case 'f': file_read = 1; break; +#else + case 'f': break; +#endif + + case 'd': + certDir = strdup(optstate->value); + certDir = SECU_ConfigDirectory(certDir); + break; + + case 'm': + multiplier = atoi(optstate->value); + if (multiplier < 0) + multiplier = 0; + break; + + case 'n': nickname = strdup(optstate->value); break; + + case 'o': override = 1; break; + + case 'p': port = strdup(optstate->value); break; + + case 'q': pingServerFirst = PR_TRUE; break; + + case 'v': verbose++; break; + + case 'w': + password = PORT_Strdup(optstate->value); + useCommandLinePassword = PR_TRUE; + break; + + case 'x': useExportPolicy = 1; break; + } + } + if (optstatus == PL_OPT_BAD) + Usage(progName); + + if (!host || !port) Usage(progName); + + if (!certDir) { + certDir = SECU_DefaultSSLDir(); /* Look in $SSL_DIR */ + certDir = SECU_ConfigDirectory(certDir); /* call even if it's NULL */ + } + + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + + /* set our password function */ + if ( useCommandLinePassword ) { + PK11_SetPasswordFunc(ownPasswd); + } else { + PK11_SetPasswordFunc(SECU_GetModulePassword); + } + + /* open the cert DB, the key DB, and the secmod DB. */ + rv = NSS_Init(certDir); + if (rv != SECSuccess) { + SECU_PrintError(progName, "unable to open cert database"); +#if 0 + rv = CERT_OpenVolatileCertDB(handle); + CERT_SetDefaultCertDB(handle); +#else + return 1; +#endif + } + handle = CERT_GetDefaultCertDB(); + + /* set the policy bits true for all the cipher suites. */ + if (useExportPolicy) + NSS_SetExportPolicy(); + else + NSS_SetDomesticPolicy(); + + /* all the SSL2 and SSL3 cipher suites are enabled by default. */ + if (cipherString) { + /* disable all the ciphers, then enable the ones we want. */ + disableAllSSLCiphers(); + } + + /* Lookup host */ + status = PR_GetHostByName(host, buf, sizeof(buf), &hp); + if (status != PR_SUCCESS) { + SECU_PrintError(progName, "error looking up host"); + return 1; + } + if (PR_EnumerateHostEnt(0, &hp, atoi(port), &addr) == -1) { + SECU_PrintError(progName, "error looking up host address"); + return 1; + } + + ip = PR_ntohl(addr.inet.ip); + PRINTF("%s: connecting to %s:%d (address=%d.%d.%d.%d)\n", + progName, host, PR_ntohs(addr.inet.port), + (ip >> 24) & 0xff, + (ip >> 16) & 0xff, + (ip >> 8) & 0xff, + (ip >> 0) & 0xff); + + if (pingServerFirst) { + int iter = 0; + PRErrorCode err; + do { + s = PR_NewTCPSocket(); + if (s == NULL) { + SECU_PrintError(progName, "Failed to create a TCP socket"); + } + opt.option = PR_SockOpt_Nonblocking; + opt.value.non_blocking = PR_FALSE; + prStatus = PR_SetSocketOption(s, &opt); + if (prStatus != PR_SUCCESS) { + PR_Close(s); + SECU_PrintError(progName, + "Failed to set blocking socket option"); + return 1; + } + prStatus = PR_Connect(s, &addr, PR_INTERVAL_NO_TIMEOUT); + if (prStatus == PR_SUCCESS) { + PR_Shutdown(s, PR_SHUTDOWN_BOTH); + PR_Close(s); + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + PR_Cleanup(); + return 0; + } + err = PR_GetError(); + if ((err != PR_CONNECT_REFUSED_ERROR) && + (err != PR_CONNECT_RESET_ERROR)) { + SECU_PrintError(progName, "TCP Connection failed"); + return 1; + } + PR_Close(s); + PR_Sleep(PR_MillisecondsToInterval(WAIT_INTERVAL)); + } while (++iter < MAX_WAIT_FOR_SERVER); + SECU_PrintError(progName, + "Client timed out while waiting for connection to server"); + return 1; + } + + /* Create socket */ + s = PR_NewTCPSocket(); + if (s == NULL) { + SECU_PrintError(progName, "error creating socket"); + return 1; + } + + opt.option = PR_SockOpt_Nonblocking; + opt.value.non_blocking = PR_TRUE; + PR_SetSocketOption(s, &opt); + /*PR_SetSocketOption(PR_GetSpecialFD(PR_StandardInput), &opt);*/ + + s = SSL_ImportFD(NULL, s); + if (s == NULL) { + SECU_PrintError(progName, "error importing socket"); + return 1; + } + + rv = SSL_OptionSet(s, SSL_SECURITY, 1); + if (rv != SECSuccess) { + SECU_PrintError(progName, "error enabling socket"); + return 1; + } + + rv = SSL_OptionSet(s, SSL_HANDSHAKE_AS_CLIENT, 1); + if (rv != SECSuccess) { + SECU_PrintError(progName, "error enabling client handshake"); + return 1; + } + + /* all the SSL2 and SSL3 cipher suites are enabled by default. */ + if (cipherString) { + int ndx; + + while (0 != (ndx = *cipherString++)) { + int *cptr; + int cipher; + + if (! isalpha(ndx)) + Usage(progName); + cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites; + for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; ) + /* do nothing */; + if (cipher) { + SECStatus status; + status = SSL_CipherPrefSet(s, cipher, SSL_ALLOWED); + if (status != SECSuccess) + SECU_PrintError(progName, "SSL_CipherPrefSet()"); + } + } + } + + rv = SSL_OptionSet(s, SSL_ENABLE_SSL2, !disableSSL2); + if (rv != SECSuccess) { + SECU_PrintError(progName, "error enabling SSLv2 "); + return 1; + } + + rv = SSL_OptionSet(s, SSL_ENABLE_SSL3, !disableSSL3); + if (rv != SECSuccess) { + SECU_PrintError(progName, "error enabling SSLv3 "); + return 1; + } + + rv = SSL_OptionSet(s, SSL_ENABLE_TLS, !disableTLS); + if (rv != SECSuccess) { + SECU_PrintError(progName, "error enabling TLS "); + return 1; + } + + /* disable ssl2 and ssl2-compatible client hellos. */ + rv = SSL_OptionSet(s, SSL_V2_COMPATIBLE_HELLO, !disableSSL2); + if (rv != SECSuccess) { + SECU_PrintError(progName, "error disabling v2 compatibility"); + return 1; + } + + if (useCommandLinePassword) { + SSL_SetPKCS11PinArg(s, password); + } + + SSL_AuthCertificateHook(s, SSL_AuthCertificate, (void *)handle); + if (override) { + SSL_BadCertHook(s, ownBadCertHandler, NULL); + } + SSL_GetClientAuthDataHook(s, NSS_GetClientAuthData, (void *)nickname); + SSL_HandshakeCallback(s, handshakeCallback, NULL); + SSL_SetURL(s, host); + + /* Try to connect to the server */ + status = PR_Connect(s, &addr, PR_INTERVAL_NO_TIMEOUT); + if (status != PR_SUCCESS) { + if (PR_GetError() == PR_IN_PROGRESS_ERROR) { + if (verbose) + SECU_PrintError(progName, "connect"); + milliPause(50 * multiplier); + pollset[0].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; + pollset[0].out_flags = 0; + pollset[0].fd = s; + while(1) { + PRINTF("%s: about to call PR_Poll for connect completion!\n", progName); + filesReady = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT); + if (filesReady < 0) { + SECU_PrintError(progName, "unable to connect (poll)"); + return 1; + } + PRINTF("%s: PR_Poll returned 0x%02x for socket out_flags.\n", + progName, pollset[0].out_flags); + if (filesReady == 0) { /* shouldn't happen! */ + PRINTF("%s: PR_Poll returned zero!\n", progName); + return 1; + } + /* Must milliPause between PR_Poll and PR_GetConnectStatus, + * Or else winsock gets mighty confused. + * Sleep(0); + */ + milliPause(1); + status = PR_GetConnectStatus(pollset); + if (status == PR_SUCCESS) { + break; + } + if (PR_GetError() != PR_IN_PROGRESS_ERROR) { + SECU_PrintError(progName, "unable to connect (poll)"); + return 1; + } + SECU_PrintError(progName, "poll"); + milliPause(50 * multiplier); + } + } else { + SECU_PrintError(progName, "unable to connect"); + return 1; + } + } + + pollset[0].fd = s; + pollset[0].in_flags = PR_POLL_READ; + pollset[1].fd = PR_GetSpecialFD(PR_StandardInput); + pollset[1].in_flags = PR_POLL_READ; + npds = 2; + std_out = PR_GetSpecialFD(PR_StandardOutput); + + + if (file_read) { + pollset[1].out_flags = PR_POLL_READ; + npds=1; + } + + /* + ** Select on stdin and on the socket. Write data from stdin to + ** socket, read data from socket and write to stdout. + */ + PRINTF("%s: ready...\n", progName); + + while (pollset[0].in_flags || pollset[1].in_flags) { + char buf[4000]; /* buffer for stdin */ + int nb; /* num bytes read from stdin. */ + + pollset[0].out_flags = 0; + if (!file_read) { + pollset[1].out_flags = 0; + } + + PRINTF("%s: about to call PR_Poll !\n", progName); + if (pollset[1].in_flags && file_read) { + filesReady = PR_Poll(pollset, npds, PR_INTERVAL_NO_WAIT); + filesReady++; + } else { + filesReady = PR_Poll(pollset, npds, PR_INTERVAL_NO_TIMEOUT); + } + if (filesReady < 0) { + SECU_PrintError(progName, "select failed"); + error=1; + goto done; + } + if (filesReady == 0) { /* shouldn't happen! */ + PRINTF("%s: PR_Poll returned zero!\n", progName); + return 1; + } + PRINTF("%s: PR_Poll returned!\n", progName); + if (pollset[1].in_flags) { + PRINTF("%s: PR_Poll returned 0x%02x for stdin out_flags.\n", + progName, pollset[1].out_flags); +#ifndef _WINDOWS + } + if (pollset[1].out_flags & PR_POLL_READ) { +#endif + /* Read from stdin and write to socket */ + nb = PR_Read(pollset[1].fd, buf, sizeof(buf)); + PRINTF("%s: stdin read %d bytes\n", progName, nb); + if (nb < 0) { + if (PR_GetError() != PR_WOULD_BLOCK_ERROR) { + SECU_PrintError(progName, "read from stdin failed"); + error=1; + break; + } + } else if (nb == 0) { + pollset[1].in_flags = 0; + } else { + char * bufp = buf; + PRINTF("%s: Writing %d bytes to server\n", progName, nb); + do { + PRInt32 cc = PR_Write(s, bufp, nb); + if (cc < 0) { + PRErrorCode err = PR_GetError(); + if (err != PR_WOULD_BLOCK_ERROR) { + SECU_PrintError(progName, + "write to SSL socket failed"); + error=254; + goto done; + } + cc = 0; + } + bufp += cc; + nb -= cc; + if (nb <= 0) + break; + pollset[0].in_flags = PR_POLL_WRITE | PR_POLL_EXCEPT; + pollset[0].out_flags = 0; + PRINTF("%s: about to call PR_Poll on writable socket !\n", progName); + cc = PR_Poll(pollset, 1, PR_INTERVAL_NO_TIMEOUT); + PRINTF("%s: PR_Poll returned with writable socket !\n", progName); + } while (1); + pollset[0].in_flags = PR_POLL_READ; + } + } + + if (pollset[0].in_flags) { + PRINTF("%s: PR_Poll returned 0x%02x for socket out_flags.\n", + progName, pollset[0].out_flags); + } + if ( (pollset[0].out_flags & PR_POLL_READ) + || (pollset[0].out_flags & PR_POLL_ERR) +#ifdef PR_POLL_HUP + || (pollset[0].out_flags & PR_POLL_HUP) +#endif + ) { + /* Read from socket and write to stdout */ + nb = PR_Read(pollset[0].fd, buf, sizeof(buf)); + PRINTF("%s: Read from server %d bytes\n", progName, nb); + if (nb < 0) { + if (PR_GetError() != PR_WOULD_BLOCK_ERROR) { + SECU_PrintError(progName, "read from socket failed"); + error=1; + goto done; + } + } else if (nb == 0) { + /* EOF from socket... bye bye */ + pollset[0].in_flags = 0; + } else { + PR_Write(std_out, buf, nb); + puts("\n\n"); + } + } + milliPause(50 * multiplier); + } + + done: + PR_Close(s); + SSL_ClearSessionCache(); + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + + PR_Cleanup(); + return error; +} diff --git a/security/nss/cmd/ttformat/Makefile b/security/nss/cmd/ttformat/Makefile new file mode 100644 index 000000000..f2a407990 --- /dev/null +++ b/security/nss/cmd/ttformat/Makefile @@ -0,0 +1,74 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### +include ../platlibs.mk + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + + + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + + +include ../platrules.mk + diff --git a/security/nss/cmd/ttformat/manifest.mn b/security/nss/cmd/ttformat/manifest.mn new file mode 100644 index 000000000..c63d5b052 --- /dev/null +++ b/security/nss/cmd/ttformat/manifest.mn @@ -0,0 +1,48 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +DEFINES += -DNSPR20 + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +CSRCS = ttformat.c + +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = seccmd dbm + +PROGRAM = ttformat + diff --git a/security/nss/cmd/ttformat/nClient b/security/nss/cmd/ttformat/nClient new file mode 100755 index 000000000..aab8402bd --- /dev/null +++ b/security/nss/cmd/ttformat/nClient @@ -0,0 +1,49 @@ +# /bin/ksh +# +# nClient -- run the nss test strsclnt for performance testing +# +# syntax: nClient [options] +# +# where: options are: +# any valid command line option for strsclnt +# Note that some options are set by this script! +# +# Description: +# nClient runs the nss test program "strsclnt" for purposes of +# gathering performance data. +# +# some shell variables are set at the top of the script +# you may have to change these, depending on the host you +# are running on and other "stuff". caveat emptor. +# +# You will have to tinker with this script to get it to +# run for you. +# +# See also: nServ +# +# --- begin nClient ------------------------------------------------------- +baseDir=/home/lorenzo/nss-raw/mozilla +# +# shell variables for running strsclnt +# +export HOST=`hostname -s` +export DOMSUF=red.iplanet.com +serverHost=dbldog +nssDB=${baseDir}/tests_results/security/${HOST}.1/client +nssHost=${HOST}.red.iplanet.com +pushd ${baseDir}/security/nss/tests/common +objDir=`gmake objdir_name` +popd +# +# +nssOptions="-p 12944 ${serverHost}.red.iplanet.com" +export LD_LIBRARY_PATH=${baseDir}/dist/${objDir}/lib +clientProg=${baseDir}/security/nss/cmd/strsclnt/${objDir}/strsclnt +# +# do the test +# +nssCommand="${clientProg} -d ${nssDB} ${nssOptions}" +echo $nssCommand $* +${nssCommand} $* & +# +# --- end nClient -------------------------------------------------------- diff --git a/security/nss/cmd/ttformat/nServ b/security/nss/cmd/ttformat/nServ new file mode 100755 index 000000000..ddf51b0e8 --- /dev/null +++ b/security/nss/cmd/ttformat/nServ @@ -0,0 +1,49 @@ +# /bin/ksh +# +# nServ -- run the nss test selfserv for performance testing +# +# syntax: nServ [options] +# +# where: options are: +# Valid arguments to the selfserv program +# Note that this script sets some options +# +# Description: +# nServ runs the nss test program "selfserv" for purposes of +# gathering performance data. +# +# some shell variables are set at the top of the script +# you may have to change these, depending on the host you +# are running on and other "stuff". caveat emptor. +# +# See also: nClinet +# +# --- begin nServ ------------------------------------------------------- +# +baseDir=/home/lorenzo/nss-server/mozilla +# +# shell variables for running selfserv +# +export HOST=`hostname -s` +export DOMSUF=red.iplanet.com +nssDB=${baseDir}/tests_results/security/${HOST}.1/server +nssHost=${HOST}.red.iplanet.com +nssOptions="-p 12944 -w nss" +pushd ${baseDir}/security/nss/tests/common +objDir=`gmake objdir_name` +popd +export LD_LIBRARY_PATH=${baseDir}/dist/${objDir}/lib +# +# shell variables for capturing instrumentation data +# +export NSPR_LOG_MODULES=TestCase:6 +export NSPR_LOG_FILE=xxxLogfile +# +# do the test +# +nssCommand="${baseDir}/dist/${objDir}/bin/selfserv -d ${nssDB} -n ${nssHost} ${nssOptions}" +echo $nssCommand +${nssCommand} $* & +# xxgdb ${baseDir}/dist/${objDir}/bin/selfserv +# +# --- end nServ ------------------------------------------------------- diff --git a/security/nss/cmd/ttformat/redux.pl b/security/nss/cmd/ttformat/redux.pl new file mode 100755 index 000000000..ccc13c24a --- /dev/null +++ b/security/nss/cmd/ttformat/redux.pl @@ -0,0 +1,77 @@ +# +# redux.pl -- general nss trace data extraction +# +# syntax: redux.pl +# +# redux.pl reads a file of formatted trace table records from stdin +# The trace records are formatted by nssilock.c +# redux.pl parses the lines and accumulates data in a hash +# When finished with stdin, redux.pl traverses the hash and emits +# the accumulated data. +# +# Operation: +# read stdin, accumulate in a hash by file, line, type. +# traverse the hash, reporting data. +# +# raw data format: +# thredid op ltype callTime heldTime lock line file +# +# Notes: +# After running redux.pl, sort the report on column 4 in decending sequence +# to see where the lock contention is. +# +# +# ----------------------------------------------------------------------- +use Getopt::Std; + +getopts("h") || die "redux.pl: unrecognized command option"; + + +# ----------------------------------------------------------------------- +# read stdin to exhaustion +while ( <STDIN> ) { + $recordCount++; +# next if ($recordCount < 36000 ); # skip initialization records + chomp; + ($thredid, $op, $ltype, $callTime, $heldTime, $lock, $line, $file) = split; + +# select out un-interesting lines +# next if (( $callTime < $opt_c ) && ( $heldTime < $opt_h )); +# print $_, "\n"; + +# count general stats + $interesting++; + +# format the key + $hashKey = $file ." ". $line ." ". $ltype; + +# Update the data in the hash entry + $theData = $theHash{$hashKey}; # read it if it already exists + ( $hCount, $hcallTime, $hheldTime, $hcallMax, $hheldMax ) = split(/\s+/, $theData ); + $hCount++; + $hcallTime += $callTime; + $hheldTime += $heldTime; + $hcallMax = ( $hcallMax > $callTime )? $hcallMax : $callTime; + $hheldMax = ( $hheldMax > $heldTime )? $hheldMax : $heldTime; + +# Write theData back to the hash + $theData = $hCount." ".$hcallTime." ".$hheldTime." ".$hcallMax." ".$hheldMax; + $theHash{$hashKey} = $theData; +} # end while() + +# ----------------------------------------------------------------------- +# traverse theHash + printf("%-16s %6s %-16s %8s %8s %8s %8s %8s\n", + "File","line","ltype","hits","calltim","heldtim","callmax","heldmax" ); +while (($hashKey,$theData) = each(%theHash)) { + $hashElements++; + ($file, $line, $ltype) = split(/\s+/, $hashKey ); + ( $hCount, $hcallTime, $hheldTime, $hcallMax, $hheldMax ) = split(/\s+/, $theData ); + printf("%-16s %6d %-16s %8d %8d %8d %8d %8d\n", + $file, $line, $ltype, $hCount, $hcallTime, $hheldTime, $hcallMax, $hheldMax ); +} # end while() + +# ----------------------------------------------------------------------- +# dump global statistics +printf ("Record count: %d\n", $recordCount ); +printf("Interesting: %d, HashElements: %d\n", $interesting, $hashElements); diff --git a/security/nss/cmd/ttformat/reduxhwm.pl b/security/nss/cmd/ttformat/reduxhwm.pl new file mode 100644 index 000000000..f442ff4e4 --- /dev/null +++ b/security/nss/cmd/ttformat/reduxhwm.pl @@ -0,0 +1,33 @@ +# +# reduxhwm.pl -- analyze highwatermark data in xxxLogfile +# +# example interesting line in xxxLogfile +# 1026[8154da0]: selfserv: Launched thread in slot 37, highWaterMark: 63 +# +# +# +while ( <STDIN> ) { + chomp; + ($proc, $who, $launched, $thread, $in, $slotx, $slot, $hwm, $highwatermark) = split; + if ( $launched == "Launched" ) { + next if ( $slot == 0 ); + $notInteresting++; + if ( $hwmMax < $highwatermark ){ + $hwmMax = $highwatermark; + } + $hwmArray[$slot] += 1; + $interesting++; + } +} # end while() + +printf ("Interesteing: %d\n", $interesting ); +printf ("Not Interesting: %d\n", $notInteresting - $interesting ); + +foreach $element (@hwmArray) { + $percent = 100*($element / $interesting); + $percentTotal += $percent; + printf("Slot %2d: %d hits, %2.2f percent, %2.2f total percent\n", $i, $element, $percent, $percentTotal ); + $i++; +} +printf("Sum of percentages: %3.2f\n", $percentTotal ); +# --- end --- diff --git a/security/nss/cmd/ttformat/ttformat.c b/security/nss/cmd/ttformat/ttformat.c new file mode 100644 index 000000000..7fcf04f86 --- /dev/null +++ b/security/nss/cmd/ttformat/ttformat.c @@ -0,0 +1,135 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is the Netscape Portable Runtime (NSPR). + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998-2000 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + * + * Alternatively, the contents of this file may be used under the + * terms of 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: ttformat.c +** Description: ttformat.c reads the file "xxxTTLog". xxxTTLog +** contains fixed length binary data written by nssilock. +** ttformat formats the data to a human readable form (printf) +** usable for visual scanning and for processing via a perl script. +** Output is written to stdout +** +*/ + +#include <stdio.h> +#include <stdlib.h> +#include <nssilock.h> + +/* +** struct maps enum nssILockType to character representation +*/ +struct { + nssILockType ltype; + char *name; +} ltypeNameT[] = { + { nssILockArena, "Arena" }, + { nssILockSession, "Session" }, + { nssILockObject, "Object" }, + { nssILockRefLock, "RefLock" }, + { nssILockCert, "Cert", }, + { nssILockCertDB, "CertDB" }, + { nssILockDBM, "DBM" }, + { nssILockCache, "Cache" }, + { nssILockSSL, "SSL" }, + { nssILockList, "List" }, + { nssILockSlot, "Slot" }, + { nssILockFreelist, "Freelist" }, + { nssILockOID, "OID" }, + { nssILockAttribute, "Attribute" }, + { nssILockPK11cxt, "PK11Context" }, + { nssILockRWLock, "RWLock" }, + { nssILockOther, "Other" }, + { nssILockSelfServ, "SelfServ" } +}; /* end ltypeNameT */ + +/* +** struct maps enum nssILockOp to character representation +*/ +struct { + nssILockOp op; + char *name; +} opNameT[] = { + { FlushTT, "FlushTT" }, + { NewLock, "NewLock" }, + { Lock, "Lock" }, + { Unlock, "Unlock" }, + { DestroyLock, "DestroyLock" }, + { NewCondVar, "NewCondVar" }, + { WaitCondVar, "WaitCondVar" }, + { NotifyCondVar, "NotifyCondVar" }, + { NotifyAllCondVar, "NotifyAllCondVar" }, + { DestroyCondVar, "DestroyCondVar" }, + { NewMonitor, "NewMonitor" }, + { EnterMonitor, "EnterMonitor" }, + { ExitMonitor, "ExitMonitor" }, + { Notify, "Notify" }, + { NotifyAll, "NotifyAll" }, + { Wait, "Wait" }, + { DestroyMonitor, "DestroyMonitor" } +}; /* end opNameT */ + + +int main(int argc, char *argv[]) +{ + FILE *filea; + struct pzTrace_s inBuf; + char *opName; + char *ltypeName; + int rCount = 0; + int oCount = 0; + + filea = fopen( "xxxTTLog", "r" ); + if ( NULL == filea ) { + fprintf( stderr, "ttformat: Oh drat! Can't open 'xxxTTLog'\n" ); + exit(1); + } + + while(1 == (fread( &inBuf, sizeof(inBuf), 1 , filea ))) { + ++rCount; + if ( inBuf.op > DestroyMonitor ) continue; + if ( inBuf.op < FlushTT ) continue; + + opName = opNameT[inBuf.op].name; + ltypeName = ltypeNameT[inBuf.ltype].name; + + ++oCount; + printf("%8d %18s %18s %6d %6d %12p %6d %20s\n", + inBuf.threadID, opName, ltypeName, inBuf.callTime, inBuf.heldTime, + inBuf.lock, inBuf.line, inBuf.file ); + } /* end while() */ + + fprintf( stderr, "Read: %d, Wrote: %d\n", rCount, oCount ); + return 0; +} /* main() */ +/* end ttformat.c */ diff --git a/security/nss/cmd/vfychain/Makefile b/security/nss/cmd/vfychain/Makefile new file mode 100644 index 000000000..8a0332d89 --- /dev/null +++ b/security/nss/cmd/vfychain/Makefile @@ -0,0 +1,82 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +ifeq (,$(filter-out WINNT WIN95 WIN16,$(OS_TARGET))) # omits WINCE +ifndef BUILD_OPT +LDFLAGS += /subsystem:console /profile /debug /machine:I386 /incremental:no +OS_CFLAGS += -D_CONSOLE +endif +endif + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + +#include ../platlibs.mk + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +include ../platrules.mk + diff --git a/security/nss/cmd/vfychain/manifest.mn b/security/nss/cmd/vfychain/manifest.mn new file mode 100644 index 000000000..1cdcc4de8 --- /dev/null +++ b/security/nss/cmd/vfychain/manifest.mn @@ -0,0 +1,51 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +# This next line is used by .mk files +# and gets translated into $LINCS in manifest.mnw +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = seccmd + +# DIRS = + +CSRCS = vfychain.c +DEFINES += -DDLL_PREFIX=\"$(DLL_PREFIX)\" -DDLL_SUFFIX=\"$(DLL_SUFFIX)\" + +PROGRAM = vfychain + diff --git a/security/nss/cmd/vfychain/vfychain.c b/security/nss/cmd/vfychain/vfychain.c new file mode 100644 index 000000000..91189ed19 --- /dev/null +++ b/security/nss/cmd/vfychain/vfychain.c @@ -0,0 +1,438 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/**************************************************************************** + * Read in a cert chain from one or more files, and verify the chain for + * some usage. + * * + * This code was modified from other code also kept in the NSS directory. + ****************************************************************************/ + +#include <stdio.h> +#include <string.h> + +#if defined(XP_UNIX) +#include <unistd.h> +#endif + +#include "prerror.h" + +#include "nssrenam.h" +#include "pk11func.h" +#include "seccomon.h" +#include "secutil.h" +#include "secmod.h" +#include "secitem.h" +#include "cert.h" + + +/* #include <stdlib.h> */ +/* #include <errno.h> */ +/* #include <fcntl.h> */ +/* #include <stdarg.h> */ + +#include "nspr.h" +#include "plgetopt.h" +#include "prio.h" +#include "nss.h" + +/* #include "vfyutil.h" */ + +#define RD_BUF_SIZE (60 * 1024) + +int verbose; + +char *password = NULL; + +/* Function: char * myPasswd() + * + * Purpose: This function is our custom password handler that is called by + * SSL when retreiving private certs and keys from the database. Returns a + * pointer to a string that with a password for the database. Password pointer + * should point to dynamically allocated memory that will be freed later. + */ +char * +myPasswd(PK11SlotInfo *info, PRBool retry, void *arg) +{ + char * passwd = NULL; + + if ( (!retry) && arg ) { + passwd = PORT_Strdup((char *)arg); + } + return passwd; +} + +static void +Usage(const char *progName) +{ + fprintf(stderr, + "Usage: %s [-d dbdir] certfile [certfile ...]\n", + progName); + exit(1); +} + +/************************************************************************** +** +** Error and information routines. +** +**************************************************************************/ + +void +errWarn(char *function) +{ + PRErrorCode errorNumber = PR_GetError(); + const char * errorString = SECU_Strerror(errorNumber); + + fprintf(stderr, "Error in function %s: %d\n - %s\n", + function, errorNumber, errorString); +} + +void +exitErr(char *function) +{ + errWarn(function); + /* Exit gracefully. */ + /* ignoring return value of NSS_Shutdown as code exits with 1 anyway*/ + (void) NSS_Shutdown(); + PR_Cleanup(); + exit(1); +} + +static char * +bestCertName(CERTCertificate *cert) { + if (cert->nickname) { + return cert->nickname; + } + if (cert->emailAddr) { + return cert->emailAddr; + } + return cert->subjectName; +} + +void +printCertProblems(FILE *outfile, CERTCertDBHandle *handle, + CERTCertificate *cert, PRBool checksig, + SECCertUsage certUsage, void *pinArg) +{ + CERTVerifyLog log; + CERTVerifyLogNode *node = NULL; + unsigned int depth = (unsigned int)-1; + unsigned int flags = 0; + char * errstr = NULL; + PRErrorCode err = PORT_GetError(); + + log.arena = PORT_NewArena(512); + log.head = log.tail = NULL; + log.count = 0; + CERT_VerifyCert(handle, cert, checksig, certUsage, + PR_Now(), pinArg, &log); + + if (log.count > 0) { + fprintf(outfile,"PROBLEM WITH THE CERT CHAIN:\n"); + for (node = log.head; node; node = node->next) { + if (depth != node->depth) { + depth = node->depth; + fprintf(outfile,"CERT %d. %s %s:\n", depth, + bestCertName(node->cert), + depth ? "[Certificate Authority]": ""); + if (verbose) { + const char * emailAddr; + emailAddr = CERT_GetFirstEmailAddress(node->cert); + if (emailAddr) { + fprintf(outfile,"Email Address(es): "); + do { + fprintf(outfile, "%s\n", emailAddr); + emailAddr = CERT_GetNextEmailAddress(node->cert, + emailAddr); + } while (emailAddr); + } + } + } + fprintf(outfile," ERROR %d: %s\n", node->error, + SECU_Strerror(node->error)); + errstr = NULL; + switch (node->error) { + case SEC_ERROR_INADEQUATE_KEY_USAGE: + flags = (unsigned int)node->arg; + switch (flags) { + case KU_DIGITAL_SIGNATURE: + errstr = "Cert cannot sign."; + break; + case KU_KEY_ENCIPHERMENT: + errstr = "Cert cannot encrypt."; + break; + case KU_KEY_CERT_SIGN: + errstr = "Cert cannot sign other certs."; + break; + default: + errstr = "[unknown usage]."; + break; + } + case SEC_ERROR_INADEQUATE_CERT_TYPE: + flags = (unsigned int)node->arg; + switch (flags) { + case NS_CERT_TYPE_SSL_CLIENT: + case NS_CERT_TYPE_SSL_SERVER: + errstr = "Cert cannot be used for SSL."; + break; + case NS_CERT_TYPE_SSL_CA: + errstr = "Cert cannot be used as an SSL CA."; + break; + case NS_CERT_TYPE_EMAIL: + errstr = "Cert cannot be used for SMIME."; + break; + case NS_CERT_TYPE_EMAIL_CA: + errstr = "Cert cannot be used as an SMIME CA."; + break; + case NS_CERT_TYPE_OBJECT_SIGNING: + errstr = "Cert cannot be used for object signing."; + break; + case NS_CERT_TYPE_OBJECT_SIGNING_CA: + errstr = "Cert cannot be used as an object signing CA."; + break; + default: + errstr = "[unknown usage]."; + break; + } + case SEC_ERROR_UNKNOWN_ISSUER: + case SEC_ERROR_UNTRUSTED_ISSUER: + case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: + errstr = node->cert->issuerName; + break; + default: + break; + } + if (errstr) { + fprintf(stderr," %s\n",errstr); + } + CERT_DestroyCertificate(node->cert); + } + } + PORT_SetError(err); /* restore original error code */ +} + +typedef struct certMemStr { + struct certMemStr * next; + CERTCertificate * cert; +} certMem; + +certMem * theCerts; + +void +rememberCert(CERTCertificate * cert) +{ + certMem * newCertMem = PORT_ZNew(certMem); + if (newCertMem) { + newCertMem->next = theCerts; + newCertMem->cert = cert; + theCerts = newCertMem; + } +} + +void +forgetCerts(void) +{ + certMem * oldCertMem; + while (oldCertMem = theCerts) { + theCerts = oldCertMem->next; + CERT_DestroyCertificate(oldCertMem->cert); + PORT_Free(oldCertMem); + } + theCerts = NULL; +} + + +CERTCertificate * +readCertFile(const char * fileName, PRBool isAscii) +{ + unsigned char * pb; + CERTCertificate * cert = NULL; + CERTCertDBHandle *defaultDB = NULL; + PRFileDesc* fd; + PRInt32 cc = -1; + PRInt32 total; + PRInt32 remaining; + SECItem item; + static unsigned char certBuf[RD_BUF_SIZE]; + + fd = PR_Open(fileName, PR_RDONLY, 0777); + if (!fd) { + PRIntn err = PR_GetError(); + fprintf(stderr, "open of %s failed, %d = %s\n", + fileName, err, SECU_Strerror(err)); + return cert; + } + /* read until EOF or buffer is full */ + pb = certBuf; + while (0 < (remaining = (sizeof certBuf) - (pb - certBuf))) { + cc = PR_Read(fd, pb, remaining); + if (cc == 0) + break; + if (cc < 0) { + PRIntn err = PR_GetError(); + fprintf(stderr, "read of %s failed, %d = %s\n", + fileName, err, SECU_Strerror(err)); + break; + } + /* cc > 0 */ + pb += cc; + } + PR_Close(fd); + if (cc < 0) + return cert; + if (!remaining || cc > 0) { /* file was too big. */ + fprintf(stderr, "cert file %s was too big.\n"); + return cert; + } + total = pb - certBuf; + if (!total) { /* file was empty */ + fprintf(stderr, "cert file %s was empty.\n"); + return cert; + } + if (isAscii) { + /* convert from Base64 to binary here ... someday */ + } + item.type = siBuffer; + item.data = certBuf; + item.len = total; + defaultDB = CERT_GetDefaultCertDB(); + cert = CERT_NewTempCertificate(defaultDB, &item, + NULL /* nickname */, + PR_FALSE /* isPerm */, + PR_TRUE /* copyDER */); + if (!cert) { + PRIntn err = PR_GetError(); + fprintf(stderr, "couldn't import %s, %d = %s\n", + fileName, err, SECU_Strerror(err)); + } + return cert; +} + +int +main(int argc, char *argv[], char *envp[]) +{ + char * certDir = NULL; + char * progName = NULL; + char * cipherString = NULL; + CERTCertificate * cert; + CERTCertificate * firstCert = NULL; + CERTCertDBHandle * defaultDB = NULL; + PRBool isAscii = PR_FALSE; + SECStatus secStatus; + SECCertUsage certUsage = certUsageSSLServer; + PLOptState * optstate; + PLOptStatus status; + + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + + progName = PL_strdup(argv[0]); + + optstate = PL_CreateOptState(argc, argv, "ad:ru:w:v"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch(optstate->option) { + case 0 : /* positional parameter */ goto breakout; + case 'a' : isAscii = PR_TRUE; break; + case 'd' : certDir = PL_strdup(optstate->value); break; + case 'r' : isAscii = PR_FALSE; break; + case 'u' : certUsage = (SECCertUsage)PORT_Atoi(optstate->value); break; + case 'w' : password = PL_strdup(optstate->value); break; + case 'v' : verbose++; break; + default : Usage(progName); break; + } + } +breakout: + if (status != PL_OPT_OK) + Usage(progName); + + /* Set our password function callback. */ + PK11_SetPasswordFunc(myPasswd); + + /* Initialize the NSS libraries. */ + if (certDir) { + secStatus = NSS_Init(certDir); + } else { + secStatus = NSS_NoDB_Init(NULL); + + /* load the builtins */ + SECMOD_AddNewModule("Builtins", DLL_PREFIX"nssckbi."DLL_SUFFIX, 0, 0); + } + if (secStatus != SECSuccess) { + exitErr("NSS_Init"); + } + + + while (status == PL_OPT_OK) { + switch(optstate->option) { + default : Usage(progName); break; + case 'a' : isAscii = PR_TRUE; break; + case 'r' : isAscii = PR_FALSE; break; + case 0 : /* positional parameter */ + cert = readCertFile(optstate->value, isAscii); + if (!cert) + goto punt; + rememberCert(cert); + if (!firstCert) + firstCert = cert; + break; + } + status = PL_GetNextOpt(optstate); + } + if (status == PL_OPT_BAD || !firstCert) + Usage(progName); + + /* NOW, verify the cert chain. */ + defaultDB = CERT_GetDefaultCertDB(); + secStatus = CERT_VerifyCert(defaultDB, firstCert, + PR_TRUE /* check sig */, + certUsage, + PR_Now(), + NULL, /* wincx */ + NULL); /* error log */ + + if (secStatus != SECSuccess) { + PRIntn err = PR_GetError(); + fprintf(stderr, "Chain is bad, %d = %s\n", err, SECU_Strerror(err)); + printCertProblems(stderr, defaultDB, firstCert, + PR_TRUE, certUsage, NULL); + } else { + fprintf(stderr, "Chain is good!\n"); + } + +punt: + forgetCerts(); + if (NSS_Shutdown != SECSuccess) { + exit(1); + } + PR_Cleanup(); + return 0; +} diff --git a/security/nss/cmd/vfyserv/Makefile b/security/nss/cmd/vfyserv/Makefile new file mode 100644 index 000000000..b31a4fdc8 --- /dev/null +++ b/security/nss/cmd/vfyserv/Makefile @@ -0,0 +1,84 @@ +#! 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/config.mk + +####################################################################### +# (3) Include "component" configuration information. (OPTIONAL) # +####################################################################### + +####################################################################### +# (4) Include "local" platform-dependent assignments (OPTIONAL). # +####################################################################### + +include ../platlibs.mk + +ifeq (,$(filter-out WINNT WIN95 WIN16,$(OS_TARGET))) # omits WINCE +ifndef BUILD_OPT +ifndef NS_USE_GCC +LDFLAGS += /subsystem:console /profile /debug /machine:I386 /incremental:no +endif +OS_CFLAGS += -D_CONSOLE +endif +endif + + +####################################################################### +# (5) Execute "global" rules. (OPTIONAL) # +####################################################################### + +include $(CORE_DEPTH)/coreconf/rules.mk + +####################################################################### +# (6) Execute "component" rules. (OPTIONAL) # +####################################################################### + +#include ../platlibs.mk + +####################################################################### +# (7) Execute "local" rules. (OPTIONAL). # +####################################################################### + +include ../platrules.mk + diff --git a/security/nss/cmd/vfyserv/makefile.win b/security/nss/cmd/vfyserv/makefile.win new file mode 100644 index 000000000..6cf6c12cf --- /dev/null +++ b/security/nss/cmd/vfyserv/makefile.win @@ -0,0 +1,130 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +VERBOSE = 1 +include <manifest.mn> + +#cannot define PROGRAM in manifest compatibly with NT and UNIX +PROGRAM = tstclnt +PROGRAM = ./$(OBJDIR)/$(PROGRAM).exe +include <$(DEPTH)\config\config.mak> + +# let manifest generate C_OBJS, it will prepend ./$(OBJDIR)/ +# rules.mak will append C_OBJS onto OBJS. +# OBJS = $(CSRCS:.c=.obj) + +# include files are looked for in $LINCS and $INCS. +# $LINCS is in manifest.mnw, computed from REQUIRES= +INCS = $(INCS) \ + -I$(DEPTH)/security/lib/cert \ + -I../include \ + $(NULL) + +IGNORE_ME = \ + -I$(DEPTH)/security/lib/key \ + -I$(DEPTH)/security/lib/util \ + $(NULL) + + +WINFE = $(DEPTH)/cmd/winfe/mkfiles$(MOZ_BITS)/x86Dbg + +# these files are the content of libdbm +DBM_LIB = \ + $(WINFE)/DB.obj \ + $(WINFE)/HASH.obj \ + $(WINFE)/H_BIGKEY.obj \ + $(WINFE)/H_PAGE.obj \ + $(WINFE)/H_LOG2.obj \ + $(WINFE)/H_FUNC.obj \ + $(WINFE)/HASH_BUF.obj \ + $(NULL) + +MOZ_LIBS = \ + $(WINFE)/ALLXPSTR.obj \ + $(WINFE)/XP_ERROR.obj \ + $(WINFE)/XPASSERT.obj \ + $(WINFE)/XP_REG.obj \ + $(WINFE)/XP_TRACE.obj \ + $(DBM_LIB) \ + $(WINFE)/XP_STR.obj \ + $(WINFE)/MKTEMP.obj \ + $(NULL) + +SEC_LIBS = \ + $(DIST)/lib/cert$(MOZ_BITS).lib \ + $(DIST)/lib/crypto$(MOZ_BITS).lib \ + $(DIST)/lib/hash$(MOZ_BITS).lib \ + $(DIST)/lib/key$(MOZ_BITS).lib \ + $(DIST)/lib/pkcs7$(MOZ_BITS).lib \ + $(DIST)/lib/secmod$(MOZ_BITS).lib \ + $(DIST)/lib/secutl$(MOZ_BITS).lib \ + $(DIST)/lib/ssl$(MOZ_BITS).lib \ + $(NULL) + +LLFLAGS = $(LLFLAGS) \ + ../lib/$(OBJDIR)/sectool$(MOZ_BITS).lib \ + $(SEC_LIBS) \ + $(MOZ_LIBS) \ + $(DEPTH)/nspr/src/$(OBJDIR)/getopt.obj \ + $(LIBNSPR) \ + $(NULL) + + +include <$(DEPTH)\config\rules.mak> + +INSTALL = $(MAKE_INSTALL) + +objs: $(OBJS) + +$(PROGRAM):: + $(INSTALL) $(DIST)/bin/pr3240.dll ./$(OBJDIR) + +programs: $(PROGRAM) + +install:: $(TARGETS) + $(INSTALL) $(TARGETS) $(DIST)/bin + + +symbols: + @echo "CSRCS = $(CSRCS)" + @echo "INCS = $(INCS)" + @echo "OBJS = $(OBJS)" + @echo "LIBRARY = $(LIBRARY)" + @echo "PROGRAM = $(PROGRAM)" + @echo "TARGETS = $(TARGETS)" + @echo "DIST = $(DIST)" + @echo "VERSION_NUMBER = $(VERSION_NUMBER)" + @echo "WINFE = $(WINFE)" + @echo "DBM_LIB = $(DBM_LIB)" + @echo "INSTALL = $(INSTALL)" + diff --git a/security/nss/cmd/vfyserv/manifest.mn b/security/nss/cmd/vfyserv/manifest.mn new file mode 100644 index 000000000..ccbca1d75 --- /dev/null +++ b/security/nss/cmd/vfyserv/manifest.mn @@ -0,0 +1,51 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +# MODULE public and private header directories are implicitly REQUIRED. +MODULE = nss + +# This next line is used by .mk files +# and gets translated into $LINCS in manifest.mnw +# The MODULE is always implicitly required. +# Listing it here in REQUIRES makes it appear twice in the cc command line. +REQUIRES = seccmd dbm + +# DIRS = + +CSRCS = vfyserv.c vfyutil.c +DEFINES += -DDLL_PREFIX=\"$(DLL_PREFIX)\" -DDLL_SUFFIX=\"$(DLL_SUFFIX)\" + +PROGRAM = vfyserv + diff --git a/security/nss/cmd/vfyserv/vfyserv.c b/security/nss/cmd/vfyserv/vfyserv.c new file mode 100644 index 000000000..288319dcd --- /dev/null +++ b/security/nss/cmd/vfyserv/vfyserv.c @@ -0,0 +1,458 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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. + */ + +/**************************************************************************** + * SSL client program that tests a server for proper operation of SSL2, * + * SSL3, and TLS. Test propder certificate installation. * + * * + * This code was modified from the SSLSample code also kept in the NSS * + * directory. * + ****************************************************************************/ + +#include <stdio.h> +#include <string.h> + +#if defined(XP_UNIX) +#include <unistd.h> +#endif + +#include "prerror.h" + +#include "pk11func.h" +#include "secmod.h" +#include "secitem.h" + + +#include <stdlib.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> + +#include "nspr.h" +#include "plgetopt.h" +#include "prio.h" +#include "prnetdb.h" +#include "nss.h" + +#include "vfyserv.h" + +#define RD_BUF_SIZE (60 * 1024) + +extern int ssl2CipherSuites[]; +extern int ssl3CipherSuites[]; + +GlobalThreadMgr threadMGR; +char *certNickname = NULL; +char *hostName = NULL; +char *password = NULL; +unsigned short port = 0; + +static void +Usage(const char *progName) +{ + fprintf(stderr, + "Usage: %s [-p port] [-c connections] [-C cipher(s)] hostname\n", + progName); + exit(1); +} + +PRFileDesc * +setupSSLSocket(PRNetAddr *addr) +{ + PRFileDesc *tcpSocket; + PRFileDesc *sslSocket; + PRSocketOptionData socketOption; + PRStatus prStatus; + SECStatus secStatus; + + + tcpSocket = PR_NewTCPSocket(); + if (tcpSocket == NULL) { + errWarn("PR_NewTCPSocket"); + } + + /* Make the socket blocking. */ + socketOption.option = PR_SockOpt_Nonblocking; + socketOption.value.non_blocking = PR_FALSE; + + prStatus = PR_SetSocketOption(tcpSocket, &socketOption); + if (prStatus != PR_SUCCESS) { + errWarn("PR_SetSocketOption"); + goto loser; + } + + + /* Import the socket into the SSL layer. */ + sslSocket = SSL_ImportFD(NULL, tcpSocket); + if (!sslSocket) { + errWarn("SSL_ImportFD"); + goto loser; + } + + /* Set configuration options. */ + secStatus = SSL_OptionSet(sslSocket, SSL_SECURITY, PR_TRUE); + if (secStatus != SECSuccess) { + errWarn("SSL_OptionSet:SSL_SECURITY"); + goto loser; + } + + secStatus = SSL_OptionSet(sslSocket, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE); + if (secStatus != SECSuccess) { + errWarn("SSL_OptionSet:SSL_HANDSHAKE_AS_CLIENT"); + goto loser; + } + + /* Set SSL callback routines. */ + secStatus = SSL_GetClientAuthDataHook(sslSocket, + (SSLGetClientAuthData)myGetClientAuthData, + (void *)certNickname); + if (secStatus != SECSuccess) { + errWarn("SSL_GetClientAuthDataHook"); + goto loser; + } + + secStatus = SSL_AuthCertificateHook(sslSocket, + (SSLAuthCertificate)myAuthCertificate, + (void *)CERT_GetDefaultCertDB()); + if (secStatus != SECSuccess) { + errWarn("SSL_AuthCertificateHook"); + goto loser; + } + + secStatus = SSL_BadCertHook(sslSocket, + (SSLBadCertHandler)myBadCertHandler, NULL); + if (secStatus != SECSuccess) { + errWarn("SSL_BadCertHook"); + goto loser; + } + + secStatus = SSL_HandshakeCallback(sslSocket, + (SSLHandshakeCallback)myHandshakeCallback, + NULL); + if (secStatus != SECSuccess) { + errWarn("SSL_HandshakeCallback"); + goto loser; + } + + return sslSocket; + +loser: + + PR_Close(tcpSocket); + return NULL; +} + + +const char requestString[] = {"GET /testfile HTTP/1.0\r\n\r\n" }; + +SECStatus +handle_connection(PRFileDesc *sslSocket, int connection) +{ + int countRead = 0; + PRInt32 numBytes; + char *readBuffer; + + readBuffer = PORT_Alloc(RD_BUF_SIZE); + if (!readBuffer) { + exitErr("PORT_Alloc"); + } + + /* compose the http request here. */ + + numBytes = PR_Write(sslSocket, requestString, strlen(requestString)); + if (numBytes <= 0) { + errWarn("PR_Write"); + PR_Free(readBuffer); + readBuffer = NULL; + return SECFailure; + } + + /* read until EOF */ + while (PR_TRUE) { + numBytes = PR_Read(sslSocket, readBuffer, RD_BUF_SIZE); + if (numBytes == 0) { + break; /* EOF */ + } + if (numBytes < 0) { + errWarn("PR_Read"); + break; + } + countRead += numBytes; + } + + printSecurityInfo(stderr, sslSocket); + + PR_Free(readBuffer); + readBuffer = NULL; + + /* Caller closes the socket. */ + + fprintf(stderr, + "***** Connection %d read %d bytes total.\n", + connection, countRead); + + return SECSuccess; /* success */ +} + +#define BYTE(n,i) (((i)>>((n)*8))&0xff) + +/* one copy of this function is launched in a separate thread for each +** connection to be made. +*/ +SECStatus +do_connects(void *a, int connection) +{ + PRNetAddr *addr = (PRNetAddr *)a; + PRFileDesc *sslSocket; + PRHostEnt hostEntry; + char buffer[PR_NETDB_BUF_SIZE]; + PRStatus prStatus; + PRIntn hostenum; + PRInt32 ip; + SECStatus secStatus; + + /* Set up SSL secure socket. */ + sslSocket = setupSSLSocket(addr); + if (sslSocket == NULL) { + errWarn("setupSSLSocket"); + return SECFailure; + } + + secStatus = SSL_SetPKCS11PinArg(sslSocket, password); + if (secStatus != SECSuccess) { + errWarn("SSL_SetPKCS11PinArg"); + return secStatus; + } + + secStatus = SSL_SetURL(sslSocket, hostName); + if (secStatus != SECSuccess) { + errWarn("SSL_SetURL"); + return secStatus; + } + + /* Prepare and setup network connection. */ + prStatus = PR_GetHostByName(hostName, buffer, sizeof(buffer), &hostEntry); + if (prStatus != PR_SUCCESS) { + errWarn("PR_GetHostByName"); + return SECFailure; + } + + hostenum = PR_EnumerateHostEnt(0, &hostEntry, port, addr); + if (hostenum == -1) { + errWarn("PR_EnumerateHostEnt"); + return SECFailure; + } + + ip = PR_ntohl(addr->inet.ip); + fprintf(stderr, + "Connecting to host %s (addr %d.%d.%d.%d) on port %d\n", + hostName, BYTE(3,ip), BYTE(2,ip), BYTE(1,ip), + BYTE(0,ip), PR_ntohs(addr->inet.port)); + + prStatus = PR_Connect(sslSocket, addr, PR_INTERVAL_NO_TIMEOUT); + if (prStatus != PR_SUCCESS) { + errWarn("PR_Connect"); + return SECFailure; + } + + /* Established SSL connection, ready to send data. */ +#if 0 + secStatus = SSL_ForceHandshake(sslSocket); + if (secStatus != SECSuccess) { + errWarn("SSL_ForceHandshake"); + return secStatus; + } +#endif + + secStatus = SSL_ResetHandshake(sslSocket, /* asServer */ PR_FALSE); + if (secStatus != SECSuccess) { + errWarn("SSL_ResetHandshake"); + prStatus = PR_Close(sslSocket); + if (prStatus != PR_SUCCESS) { + errWarn("PR_Close"); + } + return secStatus; + } + + secStatus = handle_connection(sslSocket, connection); + if (secStatus != SECSuccess) { + /* error already printed out in handle_connection */ + /* errWarn("handle_connection"); */ + prStatus = PR_Close(sslSocket); + if (prStatus != PR_SUCCESS) { + errWarn("PR_Close"); + } + return secStatus; + } + + PR_Close(sslSocket); + return SECSuccess; +} + +void +client_main(unsigned short port, + int connections, + const char * hostName) +{ + int i; + SECStatus secStatus; + PRStatus prStatus; + PRInt32 rv; + PRNetAddr addr; + PRHostEnt hostEntry; + char buffer[256]; + + /* Setup network connection. */ + prStatus = PR_GetHostByName(hostName, buffer, 256, &hostEntry); + if (prStatus != PR_SUCCESS) { + exitErr("PR_GetHostByName"); + } + + rv = PR_EnumerateHostEnt(0, &hostEntry, port, &addr); + if (rv < 0) { + exitErr("PR_EnumerateHostEnt"); + } + + secStatus = launch_thread(&threadMGR, do_connects, &addr, 1); + if (secStatus != SECSuccess) { + exitErr("launch_thread"); + } + + if (connections > 1) { + /* wait for the first connection to terminate, then launch the rest. */ + reap_threads(&threadMGR); + /* Start up the connections */ + for (i = 2; i <= connections; ++i) { + secStatus = launch_thread(&threadMGR, do_connects, &addr, i); + if (secStatus != SECSuccess) { + errWarn("launch_thread"); + } + } + } + + reap_threads(&threadMGR); + destroy_thread_data(&threadMGR); +} + +int +main(int argc, char **argv) +{ + char * certDir = NULL; + char * progName = NULL; + int connections = 1; + char * cipherString = NULL; + SECStatus secStatus; + PLOptState * optstate; + PLOptStatus status; + + /* Call the NSPR initialization routines */ + PR_Init( PR_SYSTEM_THREAD, PR_PRIORITY_NORMAL, 1); + + progName = PORT_Strdup(argv[0]); + + hostName = NULL; + optstate = PL_CreateOptState(argc, argv, "C:c:d:n:p:w:"); + while ((status = PL_GetNextOpt(optstate)) == PL_OPT_OK) { + switch(optstate->option) { + case 'C' : cipherString = PL_strdup(optstate->value); break; + case 'c' : connections = PORT_Atoi(optstate->value); break; + case 'd' : certDir = PL_strdup(optstate->value); break; + case 'p' : port = PORT_Atoi(optstate->value); break; + case 'w' : password = PL_strdup(optstate->value); break; + case '\0': hostName = PL_strdup(optstate->value); break; + default : Usage(progName); + } + } + + if (port == 0) { + port = 443; + } + + if (port == 0 || hostName == NULL) + Usage(progName); + + /* Set our password function callback. */ + PK11_SetPasswordFunc(myPasswd); + + /* Initialize the NSS libraries. */ + if (certDir) { + secStatus = NSS_Init(certDir); + } else { + secStatus = NSS_NoDB_Init(NULL); + + /* load the builtins */ + SECMOD_AddNewModule("Builtins", + DLL_PREFIX"nssckbi."DLL_SUFFIX, 0, 0); + } + if (secStatus != SECSuccess) { + exitErr("NSS_Init"); + } + + /* All cipher suites except RSA_NULL_MD5 are enabled by + * Domestic Policy. */ + NSS_SetDomesticPolicy(); + SSL_CipherPrefSetDefault(SSL_RSA_WITH_NULL_MD5, PR_TRUE); + + /* all the SSL2 and SSL3 cipher suites are enabled by default. */ + if (cipherString) { + int ndx; + + /* disable all the ciphers, then enable the ones we want. */ + disableAllSSLCiphers(); + + while (0 != (ndx = *cipherString++)) { + int *cptr; + int cipher; + + if (! isalpha(ndx)) + Usage(progName); + cptr = islower(ndx) ? ssl3CipherSuites : ssl2CipherSuites; + for (ndx &= 0x1f; (cipher = *cptr++) != 0 && --ndx > 0; ) + /* do nothing */; + if (cipher) { + SSL_CipherPrefSetDefault(cipher, PR_TRUE); + } + } + } + + client_main(port, connections, hostName); + + if (NSS_Shutdown() != SECSuccess) { + exit(1); + } + + PR_Cleanup(); + PORT_Free(progName); + return 0; +} + diff --git a/security/nss/cmd/vfyserv/vfyserv.h b/security/nss/cmd/vfyserv/vfyserv.h new file mode 100644 index 000000000..e23b5e779 --- /dev/null +++ b/security/nss/cmd/vfyserv/vfyserv.h @@ -0,0 +1,182 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 SSLSAMPLE_H +#define SSLSAMPLE_H + +/* Generic header files */ + +#include <stdio.h> +#include <string.h> + +/* NSPR header files */ + +#include "nspr.h" +#include "prerror.h" +#include "prnetdb.h" + +/* NSS header files */ + +#include "pk11func.h" +#include "secitem.h" +#include "ssl.h" +#include "certt.h" +#include "nss.h" +#include "secrng.h" +#include "secder.h" +#include "key.h" +#include "sslproto.h" + +/* Custom header files */ + +/* +#include "sslerror.h" +*/ + +#define BUFFER_SIZE 10240 + +/* Declare SSL cipher suites. */ + +extern int cipherSuites[]; +extern int ssl2CipherSuites[]; +extern int ssl3CipherSuites[]; + +/* Data buffer read from a socket. */ +typedef struct DataBufferStr { + char data[BUFFER_SIZE]; + int index; + int remaining; + int dataStart; + int dataEnd; +} DataBuffer; + +/* SSL callback routines. */ + +char * myPasswd(PK11SlotInfo *info, PRBool retry, void *arg); + +SECStatus myAuthCertificate(void *arg, PRFileDesc *socket, + PRBool checksig, PRBool isServer); + +SECStatus myBadCertHandler(void *arg, PRFileDesc *socket); + +SECStatus myHandshakeCallback(PRFileDesc *socket, void *arg); + +SECStatus myGetClientAuthData(void *arg, PRFileDesc *socket, + struct CERTDistNamesStr *caNames, + struct CERTCertificateStr **pRetCert, + struct SECKEYPrivateKeyStr **pRetKey); + +/* Disable all v2/v3 SSL ciphers. */ + +void disableAllSSLCiphers(void); + + +/* Error and information utilities. */ + +void errWarn(char *function); + +void exitErr(char *function); + +void printSecurityInfo(FILE *outfile, PRFileDesc *fd); + +void printCertProblems(FILE *outfile, CERTCertDBHandle *handle, + CERTCertificate *cert, PRBool checksig, + SECCertUsage certUsage, void *pinArg); + +/* Some simple thread management routines. */ + +#define MAX_THREADS 32 + +typedef SECStatus startFn(void *a, int b); + +typedef enum { rs_idle = 0, rs_running = 1, rs_zombie = 2 } runState; + +typedef struct perThreadStr { + PRFileDesc *a; + int b; + int rv; + startFn *startFunc; + PRThread *prThread; + PRBool inUse; + runState running; +} perThread; + +typedef struct GlobalThreadMgrStr { + PRLock *threadLock; + PRCondVar *threadStartQ; + PRCondVar *threadEndQ; + perThread threads[MAX_THREADS]; + int index; + int numUsed; + int numRunning; +} GlobalThreadMgr; + +void thread_wrapper(void * arg); + +SECStatus launch_thread(GlobalThreadMgr *threadMGR, + startFn *startFunc, void *a, int b); + +SECStatus reap_threads(GlobalThreadMgr *threadMGR); + +void destroy_thread_data(GlobalThreadMgr *threadMGR); + +/* Management of locked variables. */ + +struct lockedVarsStr { + PRLock * lock; + int count; + int waiters; + PRCondVar * condVar; +}; + +typedef struct lockedVarsStr lockedVars; + +void lockedVars_Init(lockedVars *lv); + +void lockedVars_Destroy(lockedVars *lv); + +void lockedVars_WaitForDone(lockedVars *lv); + +int lockedVars_AddToCount(lockedVars *lv, int addend); + +/* Buffer stuff. */ + +static const char stopCmd[] = { "GET /stop " }; +static const char defaultHeader[] = { + "HTTP/1.0 200 OK\r\n" + "Server: SSL sample server\r\n" + "Content-type: text/plain\r\n" + "\r\n" +}; + +#endif diff --git a/security/nss/cmd/vfyserv/vfyutil.c b/security/nss/cmd/vfyserv/vfyutil.c new file mode 100644 index 000000000..10e393458 --- /dev/null +++ b/security/nss/cmd/vfyserv/vfyutil.c @@ -0,0 +1,714 @@ +/* + * The contents of this file are subject to the Mozilla Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under 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 "vfyserv.h" +#include "secerr.h" +#include "sslerr.h" +#include "nspr.h" +#include "secutil.h" + +/* Declare SSL cipher suites. */ + +int ssl2CipherSuites[] = { + SSL_EN_RC4_128_WITH_MD5, /* A */ + SSL_EN_RC4_128_EXPORT40_WITH_MD5, /* B */ + SSL_EN_RC2_128_CBC_WITH_MD5, /* C */ + SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */ + SSL_EN_DES_64_CBC_WITH_MD5, /* E */ + SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* F */ + 0 +}; + +int ssl3CipherSuites[] = { + SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA, /* a */ + SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, /* b */ + SSL_RSA_WITH_RC4_128_MD5, /* c */ + SSL_RSA_WITH_3DES_EDE_CBC_SHA, /* d */ + SSL_RSA_WITH_DES_CBC_SHA, /* e */ + SSL_RSA_EXPORT_WITH_RC4_40_MD5, /* f */ + SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, /* g */ + SSL_FORTEZZA_DMS_WITH_NULL_SHA, /* h */ + SSL_RSA_WITH_NULL_MD5, /* i */ + SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, /* j */ + SSL_RSA_FIPS_WITH_DES_CBC_SHA, /* k */ + TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, /* l */ + TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, /* m */ + SSL_RSA_WITH_RC4_128_SHA, /* n */ + TLS_DHE_DSS_WITH_RC4_128_SHA, /* o */ + SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, /* p */ + SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, /* q */ + SSL_DHE_RSA_WITH_DES_CBC_SHA, /* r */ + SSL_DHE_DSS_WITH_DES_CBC_SHA, /* s */ + TLS_DHE_DSS_WITH_AES_128_CBC_SHA, /* t */ + TLS_DHE_RSA_WITH_AES_128_CBC_SHA, /* u */ + TLS_RSA_WITH_AES_128_CBC_SHA, /* v */ + TLS_DHE_DSS_WITH_AES_256_CBC_SHA, /* w */ + TLS_DHE_RSA_WITH_AES_256_CBC_SHA, /* x */ + TLS_RSA_WITH_AES_256_CBC_SHA, /* y */ + SSL_RSA_WITH_NULL_SHA, /* z */ + 0 +}; + +/************************************************************************** +** +** SSL callback routines. +** +**************************************************************************/ + +/* Function: char * myPasswd() + * + * Purpose: This function is our custom password handler that is called by + * SSL when retreiving private certs and keys from the database. Returns a + * pointer to a string that with a password for the database. Password pointer + * should point to dynamically allocated memory that will be freed later. + */ +char * +myPasswd(PK11SlotInfo *info, PRBool retry, void *arg) +{ + char * passwd = NULL; + + if ( (!retry) && arg ) { + passwd = PORT_Strdup((char *)arg); + } + return passwd; +} + +/* Function: SECStatus myAuthCertificate() + * + * Purpose: This function is our custom certificate authentication handler. + * + * Note: This implementation is essentially the same as the default + * SSL_AuthCertificate(). + */ +SECStatus +myAuthCertificate(void *arg, PRFileDesc *socket, + PRBool checksig, PRBool isServer) +{ + + SECCertUsage certUsage; + CERTCertificate * cert; + void * pinArg; + char * hostName; + SECStatus secStatus; + + if (!arg || !socket) { + errWarn("myAuthCertificate"); + return SECFailure; + } + + /* Define how the cert is being used based upon the isServer flag. */ + + certUsage = isServer ? certUsageSSLClient : certUsageSSLServer; + + cert = SSL_PeerCertificate(socket); + + pinArg = SSL_RevealPinArg(socket); + + secStatus = CERT_VerifyCertNow((CERTCertDBHandle *)arg, + cert, + checksig, + certUsage, + pinArg); + + /* If this is a server, we're finished. */ + if (isServer || secStatus != SECSuccess) { + printCertProblems(stderr, (CERTCertDBHandle *)arg, cert, + checksig, certUsage, pinArg); + CERT_DestroyCertificate(cert); + return secStatus; + } + + /* Certificate is OK. Since this is the client side of an SSL + * connection, we need to verify that the name field in the cert + * matches the desired hostname. This is our defense against + * man-in-the-middle attacks. + */ + + /* SSL_RevealURL returns a hostName, not an URL. */ + hostName = SSL_RevealURL(socket); + + if (hostName && hostName[0]) { + secStatus = CERT_VerifyCertName(cert, hostName); + } else { + PR_SetError(SSL_ERROR_BAD_CERT_DOMAIN, 0); + secStatus = SECFailure; + } + + if (hostName) + PR_Free(hostName); + + CERT_DestroyCertificate(cert); + return secStatus; +} + +/* Function: SECStatus myBadCertHandler() + * + * Purpose: This callback is called when the incoming certificate is not + * valid. We define a certain set of parameters that still cause the + * certificate to be "valid" for this session, and return SECSuccess to cause + * the server to continue processing the request when any of these conditions + * are met. Otherwise, SECFailure is return and the server rejects the + * request. + */ +SECStatus +myBadCertHandler(void *arg, PRFileDesc *socket) +{ + + SECStatus secStatus = SECFailure; + PRErrorCode err; + + /* log invalid cert here */ + + if (!arg) { + return secStatus; + } + + *(PRErrorCode *)arg = err = PORT_GetError(); + + /* If any of the cases in the switch are met, then we will proceed */ + /* with the processing of the request anyway. Otherwise, the default */ + /* case will be reached and we will reject the request. */ + + switch (err) { + case SEC_ERROR_INVALID_AVA: + case SEC_ERROR_INVALID_TIME: + case SEC_ERROR_BAD_SIGNATURE: + case SEC_ERROR_EXPIRED_CERTIFICATE: + case SEC_ERROR_UNKNOWN_ISSUER: + case SEC_ERROR_UNTRUSTED_CERT: + case SEC_ERROR_CERT_VALID: + case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: + case SEC_ERROR_CRL_EXPIRED: + case SEC_ERROR_CRL_BAD_SIGNATURE: + case SEC_ERROR_EXTENSION_VALUE_INVALID: + case SEC_ERROR_CA_CERT_INVALID: + case SEC_ERROR_CERT_USAGES_INVALID: + case SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION: + secStatus = SECSuccess; + break; + default: + secStatus = SECFailure; + break; + } + + fprintf(stderr, "Bad certificate: %d, %s\n", err, SECU_Strerror(err)); + + return secStatus; +} + +/* Function: SECStatus ownGetClientAuthData() + * + * Purpose: This callback is used by SSL to pull client certificate + * information upon server request. + */ +SECStatus +myGetClientAuthData(void *arg, + PRFileDesc *socket, + struct CERTDistNamesStr *caNames, + struct CERTCertificateStr **pRetCert, + struct SECKEYPrivateKeyStr **pRetKey) +{ + + CERTCertificate * cert; + SECKEYPrivateKey * privKey; + char * chosenNickName = (char *)arg; + void * proto_win = NULL; + SECStatus secStatus = SECFailure; + + proto_win = SSL_RevealPinArg(socket); + + if (chosenNickName) { + cert = PK11_FindCertFromNickname(chosenNickName, proto_win); + if (cert) { + privKey = PK11_FindKeyByAnyCert(cert, proto_win); + if (privKey) { + secStatus = SECSuccess; + } else { + CERT_DestroyCertificate(cert); + } + } + } else { /* no nickname given, automatically find the right cert */ + CERTCertNicknames *names; + int i; + + names = CERT_GetCertNicknames(CERT_GetDefaultCertDB(), + SEC_CERT_NICKNAMES_USER, proto_win); + + if (names != NULL) { + for(i = 0; i < names->numnicknames; i++ ) { + + cert = PK11_FindCertFromNickname(names->nicknames[i], + proto_win); + if (!cert) { + continue; + } + + /* Only check unexpired certs */ + if (CERT_CheckCertValidTimes(cert, PR_Now(), PR_FALSE) + != secCertTimeValid ) { + CERT_DestroyCertificate(cert); + continue; + } + + secStatus = NSS_CmpCertChainWCANames(cert, caNames); + if (secStatus == SECSuccess) { + privKey = PK11_FindKeyByAnyCert(cert, proto_win); + if (privKey) { + break; + } + secStatus = SECFailure; + break; + } + CERT_FreeNicknames(names); + } /* for loop */ + } + } + + if (secStatus == SECSuccess) { + *pRetCert = cert; + *pRetKey = privKey; + } + + return secStatus; +} + +/* Function: SECStatus myHandshakeCallback() + * + * Purpose: Called by SSL to inform application that the handshake is + * complete. This function is mostly used on the server side of an SSL + * connection, although it is provided for a client as well. + * Useful when a non-blocking SSL_ReHandshake or SSL_ResetHandshake + * is used to initiate a handshake. + * + * A typical scenario would be: + * + * 1. Server accepts an SSL connection from the client without client auth. + * 2. Client sends a request. + * 3. Server determines that to service request it needs to authenticate the + * client and initiates another handshake requesting client auth. + * 4. While handshake is in progress, server can do other work or spin waiting + * for the handshake to complete. + * 5. Server is notified that handshake has been successfully completed by + * the custom handshake callback function and it can service the client's + * request. + * + * Note: This function is not implemented in this sample, as we are using + * blocking sockets. + */ +SECStatus +myHandshakeCallback(PRFileDesc *socket, void *arg) +{ + fprintf(stderr,"Handshake Complete: SERVER CONFIGURED CORRECTLY\n"); + return SECSuccess; +} + + +/************************************************************************** +** +** Routines for disabling SSL ciphers. +** +**************************************************************************/ + +void +disableAllSSLCiphers(void) +{ + const PRUint16 *cipherSuites = SSL_ImplementedCiphers; + int i = SSL_NumImplementedCiphers; + SECStatus rv; + + /* disable all the SSL3 cipher suites */ + while (--i >= 0) { + PRUint16 suite = cipherSuites[i]; + rv = SSL_CipherPrefSetDefault(suite, PR_FALSE); + if (rv != SECSuccess) { + fprintf(stderr, + "SSL_CipherPrefSetDefault didn't like value 0x%04x (i = %d)\n", + suite, i); + errWarn("SSL_CipherPrefSetDefault"); + exit(2); + } + } +} + +/************************************************************************** +** +** Error and information routines. +** +**************************************************************************/ + +void +errWarn(char *function) +{ + PRErrorCode errorNumber = PR_GetError(); + const char * errorString = SECU_Strerror(errorNumber); + + fprintf(stderr, "Error in function %s: %d\n - %s\n", + function, errorNumber, errorString); +} + +void +exitErr(char *function) +{ + errWarn(function); + /* Exit gracefully. */ + /* ignoring return value of NSS_Shutdown as code exits with 1 anyway*/ + (void) NSS_Shutdown(); + PR_Cleanup(); + exit(1); +} + +void +printSecurityInfo(FILE *outfile, PRFileDesc *fd) +{ + char * cp; /* bulk cipher name */ + char * ip; /* cert issuer DN */ + char * sp; /* cert subject DN */ + int op; /* High, Low, Off */ + int kp0; /* total key bits */ + int kp1; /* secret key bits */ + int result; + SSL3Statistics * ssl3stats = SSL_GetStatistics(); + + if (!outfile) { + outfile = stdout; + } + + result = SSL_SecurityStatus(fd, &op, &cp, &kp0, &kp1, &ip, &sp); + if (result != SECSuccess) + return; + fprintf(outfile, + " bulk cipher %s, %d secret key bits, %d key bits, status: %d\n" + " subject DN:\n %s\n" + " issuer DN:\n %s\n", cp, kp1, kp0, op, sp, ip); + PR_Free(cp); + PR_Free(ip); + PR_Free(sp); + + fprintf(outfile, + " %ld cache hits; %ld cache misses, %ld cache not reusable\n", + ssl3stats->hch_sid_cache_hits, ssl3stats->hch_sid_cache_misses, + ssl3stats->hch_sid_cache_not_ok); + +} + + +/************************************************************************** +** Begin thread management routines and data. +**************************************************************************/ + +void +thread_wrapper(void * arg) +{ + GlobalThreadMgr *threadMGR = (GlobalThreadMgr *)arg; + perThread *slot = &threadMGR->threads[threadMGR->index]; + + /* wait for parent to finish launching us before proceeding. */ + PR_Lock(threadMGR->threadLock); + PR_Unlock(threadMGR->threadLock); + + slot->rv = (* slot->startFunc)(slot->a, slot->b); + + PR_Lock(threadMGR->threadLock); + slot->running = rs_zombie; + + /* notify the thread exit handler. */ + PR_NotifyCondVar(threadMGR->threadEndQ); + + PR_Unlock(threadMGR->threadLock); +} + +SECStatus +launch_thread(GlobalThreadMgr *threadMGR, + startFn *startFunc, + void *a, + int b) +{ + perThread *slot; + int i; + + if (!threadMGR->threadStartQ) { + threadMGR->threadLock = PR_NewLock(); + threadMGR->threadStartQ = PR_NewCondVar(threadMGR->threadLock); + threadMGR->threadEndQ = PR_NewCondVar(threadMGR->threadLock); + } + PR_Lock(threadMGR->threadLock); + while (threadMGR->numRunning >= MAX_THREADS) { + PR_WaitCondVar(threadMGR->threadStartQ, PR_INTERVAL_NO_TIMEOUT); + } + for (i = 0; i < threadMGR->numUsed; ++i) { + slot = &threadMGR->threads[i]; + if (slot->running == rs_idle) + break; + } + if (i >= threadMGR->numUsed) { + if (i >= MAX_THREADS) { + /* something's really wrong here. */ + PORT_Assert(i < MAX_THREADS); + PR_Unlock(threadMGR->threadLock); + return SECFailure; + } + ++(threadMGR->numUsed); + PORT_Assert(threadMGR->numUsed == i + 1); + slot = &threadMGR->threads[i]; + } + + slot->a = a; + slot->b = b; + slot->startFunc = startFunc; + + threadMGR->index = i; + + slot->prThread = PR_CreateThread(PR_USER_THREAD, + thread_wrapper, threadMGR, + PR_PRIORITY_NORMAL, PR_GLOBAL_THREAD, + PR_JOINABLE_THREAD, 0); + + if (slot->prThread == NULL) { + PR_Unlock(threadMGR->threadLock); + printf("Failed to launch thread!\n"); + return SECFailure; + } + + slot->inUse = 1; + slot->running = 1; + ++(threadMGR->numRunning); + PR_Unlock(threadMGR->threadLock); + + return SECSuccess; +} + +SECStatus +reap_threads(GlobalThreadMgr *threadMGR) +{ + perThread * slot; + int i; + + if (!threadMGR->threadLock) + return SECSuccess; + PR_Lock(threadMGR->threadLock); + while (threadMGR->numRunning > 0) { + PR_WaitCondVar(threadMGR->threadEndQ, PR_INTERVAL_NO_TIMEOUT); + for (i = 0; i < threadMGR->numUsed; ++i) { + slot = &threadMGR->threads[i]; + if (slot->running == rs_zombie) { + /* Handle cleanup of thread here. */ + + /* Now make sure the thread has ended OK. */ + PR_JoinThread(slot->prThread); + slot->running = rs_idle; + --threadMGR->numRunning; + + /* notify the thread launcher. */ + PR_NotifyCondVar(threadMGR->threadStartQ); + } + } + } + + /* Safety Sam sez: make sure count is right. */ + for (i = 0; i < threadMGR->numUsed; ++i) { + slot = &threadMGR->threads[i]; + if (slot->running != rs_idle) { + fprintf(stderr, "Thread in slot %d is in state %d!\n", + i, slot->running); + } + } + PR_Unlock(threadMGR->threadLock); + return SECSuccess; +} + +void +destroy_thread_data(GlobalThreadMgr *threadMGR) +{ + PORT_Memset(threadMGR->threads, 0, sizeof(threadMGR->threads)); + + if (threadMGR->threadEndQ) { + PR_DestroyCondVar(threadMGR->threadEndQ); + threadMGR->threadEndQ = NULL; + } + if (threadMGR->threadStartQ) { + PR_DestroyCondVar(threadMGR->threadStartQ); + threadMGR->threadStartQ = NULL; + } + if (threadMGR->threadLock) { + PR_DestroyLock(threadMGR->threadLock); + threadMGR->threadLock = NULL; + } +} + +/************************************************************************** +** End thread management routines. +**************************************************************************/ + +void +lockedVars_Init( lockedVars * lv) +{ + lv->count = 0; + lv->waiters = 0; + lv->lock = PR_NewLock(); + lv->condVar = PR_NewCondVar(lv->lock); +} + +void +lockedVars_Destroy( lockedVars * lv) +{ + PR_DestroyCondVar(lv->condVar); + lv->condVar = NULL; + + PR_DestroyLock(lv->lock); + lv->lock = NULL; +} + +void +lockedVars_WaitForDone(lockedVars * lv) +{ + PR_Lock(lv->lock); + while (lv->count > 0) { + PR_WaitCondVar(lv->condVar, PR_INTERVAL_NO_TIMEOUT); + } + PR_Unlock(lv->lock); +} + +int /* returns count */ +lockedVars_AddToCount(lockedVars * lv, int addend) +{ + int rv; + + PR_Lock(lv->lock); + rv = lv->count += addend; + if (rv <= 0) { + PR_NotifyCondVar(lv->condVar); + } + PR_Unlock(lv->lock); + return rv; +} + +static char * +bestCertName(CERTCertificate *cert) { + if (cert->nickname) { + return cert->nickname; + } + if (cert->emailAddr) { + return cert->emailAddr; + } + return cert->subjectName; +} + +void +printCertProblems(FILE *outfile, CERTCertDBHandle *handle, + CERTCertificate *cert, PRBool checksig, + SECCertUsage certUsage, void *pinArg) +{ + CERTVerifyLog log; + CERTVerifyLogNode *node = NULL; + unsigned int depth = (unsigned int)-1; + unsigned int flags = 0; + char * errstr = NULL; + PRErrorCode err = PORT_GetError(); + + log.arena = PORT_NewArena(512); + log.head = log.tail = NULL; + log.count = 0; + CERT_VerifyCert(handle, cert, checksig, certUsage, + PR_Now(), pinArg, &log); + + if (log.count > 0) { + fprintf(outfile,"PROBLEM WITH THE CERT CHAIN:\n"); + for (node = log.head; node; node = node->next) { + if (depth != node->depth) { + depth = node->depth; + fprintf(outfile,"CERT %d. %s %s:\n", depth, + bestCertName(node->cert), + depth ? "[Certificate Authority]": ""); + } + fprintf(outfile," ERROR %d: %s\n", node->error, + SECU_Strerror(node->error)); + errstr = NULL; + switch (node->error) { + case SEC_ERROR_INADEQUATE_KEY_USAGE: + flags = (unsigned int)node->arg; + switch (flags) { + case KU_DIGITAL_SIGNATURE: + errstr = "Cert cannot sign."; + break; + case KU_KEY_ENCIPHERMENT: + errstr = "Cert cannot encrypt."; + break; + case KU_KEY_CERT_SIGN: + errstr = "Cert cannot sign other certs."; + break; + default: + errstr = "[unknown usage]."; + break; + } + case SEC_ERROR_INADEQUATE_CERT_TYPE: + flags = (unsigned int)node->arg; + switch (flags) { + case NS_CERT_TYPE_SSL_CLIENT: + case NS_CERT_TYPE_SSL_SERVER: + errstr = "Cert cannot be used for SSL."; + break; + case NS_CERT_TYPE_SSL_CA: + errstr = "Cert cannot be used as an SSL CA."; + break; + case NS_CERT_TYPE_EMAIL: + errstr = "Cert cannot be used for SMIME."; + break; + case NS_CERT_TYPE_EMAIL_CA: + errstr = "Cert cannot be used as an SMIME CA."; + break; + case NS_CERT_TYPE_OBJECT_SIGNING: + errstr = "Cert cannot be used for object signing."; + break; + case NS_CERT_TYPE_OBJECT_SIGNING_CA: + errstr = "Cert cannot be used as an object signing CA."; + break; + default: + errstr = "[unknown usage]."; + break; + } + case SEC_ERROR_UNKNOWN_ISSUER: + case SEC_ERROR_UNTRUSTED_ISSUER: + case SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE: + errstr = node->cert->issuerName; + break; + default: + break; + } + if (errstr) { + fprintf(stderr," %s\n",errstr); + } + CERT_DestroyCertificate(node->cert); + } + } + PR_SetError(err, 0); /* restore original error code */ +} diff --git a/security/nss/cmd/zlib/Makefile b/security/nss/cmd/zlib/Makefile new file mode 100644 index 000000000..fa46e6763 --- /dev/null +++ b/security/nss/cmd/zlib/Makefile @@ -0,0 +1,75 @@ +#! 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/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). # +####################################################################### + + + diff --git a/security/nss/cmd/zlib/README b/security/nss/cmd/zlib/README new file mode 100644 index 000000000..28adc90b2 --- /dev/null +++ b/security/nss/cmd/zlib/README @@ -0,0 +1,99 @@ +zlib 1.0.4 is a general purpose data compression library. All the code +is reentrant (thread safe). The data format used by the zlib library +is described by RFCs (Request for Comments) 1950 to 1952 in the files +ftp://ds.internic.net/rfc/rfc1950.txt (zlib format), rfc1951.txt (deflate +format) and rfc1952.txt (gzip format). These documents are also available in +other formats from ftp://ftp.uu.net/graphics/png/documents/zlib/zdoc-index.html + +All functions of the compression library are documented in the file +zlib.h. A usage example of the library is given in the file example.c +which also tests that the library is working correctly. Another +example is given in the file minigzip.c. The compression library itself +is composed of all source files except example.c and minigzip.c. + +To compile all files and run the test program, follow the instructions +given at the top of Makefile. In short "make test; make install" +should work for most machines. For MSDOS, use one of the special +makefiles such as Makefile.msc; for VMS, use Make_vms.com or descrip.mms. + +Questions about zlib should be sent to <zlib@quest.jpl.nasa.gov> or, +if this fails, to the addresses given below in the Copyright section. +The zlib home page is http://quest.jpl.nasa.gov/zlib/ + +The changes made in version 1.0.4 are documented in the file ChangeLog. +The main changes since 1.0.3 are: + +- In very rare conditions, deflate(s, Z_FINISH) could fail to produce an EOF + bit, so the decompressor could decompress all the correct data but went + on to attempt decompressing extra garbage data. This affected minigzip too. +- zlibVersion and gzerror return const char* (needed for DLL) +- port to RISCOS (no fdopen, no multiple dots, no unlink, no fileno) + + +A Perl interface to zlib written by Paul Marquess <pmarquess@bfsec.bt.co.uk> +is in the CPAN (Comprehensive Perl Archive Network) sites, such as: +ftp://ftp.cis.ufl.edu/pub/perl/CPAN/modules/by-module/Compress/Compress-Zlib* + + +Notes for some targets: + +- For Turbo C the small model is supported only with reduced performance to + avoid any far allocation; it was tested with -DMAX_WBITS=11 -DMAX_MEM_LEVEL=3 + +- For 64-bit Iris, deflate.c must be compiled without any optimization. + With -O, one libpng test fails. The test works in 32 bit mode (with + the -32 compiler flag). The compiler bug has been reported to SGI. + +- zlib doesn't work with gcc 2.6.3 on a DEC 3000/300LX under OSF/1 2.1 + it works when compiled with cc. + +- zlib doesn't work on HP-UX 9.05 with one cc compiler (the one not + accepting the -O option). It works with the other cc compiler. + +- To build a Windows DLL version, include in a DLL project zlib.def, zlib.rc + and all .c files except example.c and minigzip.c; compile with -DZLIB_DLL + For help on building a zlib DLL, contact Alessandro Iacopetti + <iaco@email.alessandria.alpcom.it> http://lisa.unial.it/iaco , + or contact Brad Clarke <bclarke@cyberus.ca>. + +- gzdopen is not supported on RISCOS + + +Acknowledgments: + + The deflate format used by zlib was defined by Phil Katz. The deflate + and zlib specifications were written by Peter Deutsch. Thanks to all the + people who reported problems and suggested various improvements in zlib; + they are too numerous to cite here. + +Copyright notice: + + (C) 1995-1996 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + gzip@prep.ai.mit.edu madler@alumni.caltech.edu + +If you use the zlib library in a product, we would appreciate *not* +receiving lengthy legal documents to sign. The sources are provided +for free but without warranty of any kind. The library has been +entirely written by Jean-loup Gailly and Mark Adler; it does not +include third-party code. + +If you redistribute modified sources, we would appreciate that you include +in the file ChangeLog history information documenting your changes. diff --git a/security/nss/cmd/zlib/adler32.c b/security/nss/cmd/zlib/adler32.c new file mode 100644 index 000000000..9f4afd63c --- /dev/null +++ b/security/nss/cmd/zlib/adler32.c @@ -0,0 +1,48 @@ +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ +/* This file was modified since it was taken from the zlib distribution */ +/* $Id$ */ + +#include "zlib.h" + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* ========================================================================= */ +PR_PUBLIC_API(uLong) adler32(adler, buf, len) + uLong adler; + const Bytef *buf; + uInt len; +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} diff --git a/security/nss/cmd/zlib/compress.c b/security/nss/cmd/zlib/compress.c new file mode 100644 index 000000000..3e1cc7c09 --- /dev/null +++ b/security/nss/cmd/zlib/compress.c @@ -0,0 +1,57 @@ +/* compress.c -- compress a memory buffer + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ +/* This file was modified since it was taken from the zlib distribution */ +/* $Id$ */ + +#include "zlib.h" + +/* =========================================================================== + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 8 bytes. Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ +PR_PUBLIC_API(int) compress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; +#ifdef MAXSEG_64K + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; +#endif + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + stream.opaque = (voidpf)0; + + err = deflateInit(&stream, Z_DEFAULT_COMPRESSION); + if (err != Z_OK) return err; + + err = deflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + deflateEnd(&stream); + return err == Z_OK ? Z_BUF_ERROR : err; + } + *destLen = stream.total_out; + + err = deflateEnd(&stream); + return err; +} diff --git a/security/nss/cmd/zlib/config.mk b/security/nss/cmd/zlib/config.mk new file mode 100644 index 000000000..a1c67fdb4 --- /dev/null +++ b/security/nss/cmd/zlib/config.mk @@ -0,0 +1,70 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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. +# + +# +# Currently, override TARGETS variable so that only static libraries +# are specifed as dependencies within rules.mk. +# + +TARGETS = $(LIBRARY) +SHARED_LIBRARY = +IMPORT_LIBRARY = +PROGRAM = + +####################################################################### +# Set the LDFLAGS value to encompass all normal link options, all # +# library names, and all special system linking options # +####################################################################### + +SECTOOLS_LIBS = $(LDOPTS) $(LIBSSL) $(LIBPKCS7) $(LIBCERT) $(LIBKEY) \ + $(LIBSECMOD) $(LIBCRYPTO) $(LIBSECUTIL) $(LIBSECMOD) $(LIBSSL) \ + $(LIBPKCS7) $(LIBCERT) $(LIBKEY) $(LIBCRYPTO) $(LIBSECUTIL) \ + $(LIBHASH) $(LIBDBM) $(DLLPLC) $(DLLPLDS) $(DLLPR) $(DLLSYSTEM) + +ifeq ($(OS_TARGET),AIX) + OS_LIBS += $(SECTOOLS_LIBS) +endif + +ifeq ($(OS_TARGET),NCR) + OS_LIBS += $(SECTOOLS_LIBS) +endif + +ifeq ($(OS_TARGET),SCO_SV) + OS_LIBS += $(SECTOOLS_LIBS) +endif + +LDFLAGS += $(SECTOOLS_LIBS) + + + + diff --git a/security/nss/cmd/zlib/crc32.c b/security/nss/cmd/zlib/crc32.c new file mode 100644 index 000000000..398871cf8 --- /dev/null +++ b/security/nss/cmd/zlib/crc32.c @@ -0,0 +1,162 @@ +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ +/* This file was modified since it was taken from the zlib distribution */ +/* $Id$ */ + +#include "zlib.h" + +#define local static + +#ifdef DYNAMIC_CRC_TABLE + +local int crc_table_empty = 1; +local uLongf crc_table[256]; +local void make_crc_table OF((void)); + +/* + Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The table is simply the CRC of all possible eight bit values. This is all + the information needed to generate CRC's on data a byte at a time for all + combinations of CRC register values and incoming bytes. +*/ +local void make_crc_table() +{ + uLong c; + int n, k; + uLong poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320L) */ + poly = 0L; + for (n = 0; n < sizeof(p)/sizeof(Byte); n++) + poly |= 1L << (31 - p[n]); + + for (n = 0; n < 256; n++) + { + c = (uLong)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[n] = c; + } + crc_table_empty = 0; +} +#else +/* ======================================================================== + * Table of CRC-32's of all single-byte values (made by make_crc_table) + */ +local uLongf crc_table[256] = { + 0x00000000UL, 0x77073096UL, 0xee0e612cUL, 0x990951baUL, 0x076dc419UL, + 0x706af48fUL, 0xe963a535UL, 0x9e6495a3UL, 0x0edb8832UL, 0x79dcb8a4UL, + 0xe0d5e91eUL, 0x97d2d988UL, 0x09b64c2bUL, 0x7eb17cbdUL, 0xe7b82d07UL, + 0x90bf1d91UL, 0x1db71064UL, 0x6ab020f2UL, 0xf3b97148UL, 0x84be41deUL, + 0x1adad47dUL, 0x6ddde4ebUL, 0xf4d4b551UL, 0x83d385c7UL, 0x136c9856UL, + 0x646ba8c0UL, 0xfd62f97aUL, 0x8a65c9ecUL, 0x14015c4fUL, 0x63066cd9UL, + 0xfa0f3d63UL, 0x8d080df5UL, 0x3b6e20c8UL, 0x4c69105eUL, 0xd56041e4UL, + 0xa2677172UL, 0x3c03e4d1UL, 0x4b04d447UL, 0xd20d85fdUL, 0xa50ab56bUL, + 0x35b5a8faUL, 0x42b2986cUL, 0xdbbbc9d6UL, 0xacbcf940UL, 0x32d86ce3UL, + 0x45df5c75UL, 0xdcd60dcfUL, 0xabd13d59UL, 0x26d930acUL, 0x51de003aUL, + 0xc8d75180UL, 0xbfd06116UL, 0x21b4f4b5UL, 0x56b3c423UL, 0xcfba9599UL, + 0xb8bda50fUL, 0x2802b89eUL, 0x5f058808UL, 0xc60cd9b2UL, 0xb10be924UL, + 0x2f6f7c87UL, 0x58684c11UL, 0xc1611dabUL, 0xb6662d3dUL, 0x76dc4190UL, + 0x01db7106UL, 0x98d220bcUL, 0xefd5102aUL, 0x71b18589UL, 0x06b6b51fUL, + 0x9fbfe4a5UL, 0xe8b8d433UL, 0x7807c9a2UL, 0x0f00f934UL, 0x9609a88eUL, + 0xe10e9818UL, 0x7f6a0dbbUL, 0x086d3d2dUL, 0x91646c97UL, 0xe6635c01UL, + 0x6b6b51f4UL, 0x1c6c6162UL, 0x856530d8UL, 0xf262004eUL, 0x6c0695edUL, + 0x1b01a57bUL, 0x8208f4c1UL, 0xf50fc457UL, 0x65b0d9c6UL, 0x12b7e950UL, + 0x8bbeb8eaUL, 0xfcb9887cUL, 0x62dd1ddfUL, 0x15da2d49UL, 0x8cd37cf3UL, + 0xfbd44c65UL, 0x4db26158UL, 0x3ab551ceUL, 0xa3bc0074UL, 0xd4bb30e2UL, + 0x4adfa541UL, 0x3dd895d7UL, 0xa4d1c46dUL, 0xd3d6f4fbUL, 0x4369e96aUL, + 0x346ed9fcUL, 0xad678846UL, 0xda60b8d0UL, 0x44042d73UL, 0x33031de5UL, + 0xaa0a4c5fUL, 0xdd0d7cc9UL, 0x5005713cUL, 0x270241aaUL, 0xbe0b1010UL, + 0xc90c2086UL, 0x5768b525UL, 0x206f85b3UL, 0xb966d409UL, 0xce61e49fUL, + 0x5edef90eUL, 0x29d9c998UL, 0xb0d09822UL, 0xc7d7a8b4UL, 0x59b33d17UL, + 0x2eb40d81UL, 0xb7bd5c3bUL, 0xc0ba6cadUL, 0xedb88320UL, 0x9abfb3b6UL, + 0x03b6e20cUL, 0x74b1d29aUL, 0xead54739UL, 0x9dd277afUL, 0x04db2615UL, + 0x73dc1683UL, 0xe3630b12UL, 0x94643b84UL, 0x0d6d6a3eUL, 0x7a6a5aa8UL, + 0xe40ecf0bUL, 0x9309ff9dUL, 0x0a00ae27UL, 0x7d079eb1UL, 0xf00f9344UL, + 0x8708a3d2UL, 0x1e01f268UL, 0x6906c2feUL, 0xf762575dUL, 0x806567cbUL, + 0x196c3671UL, 0x6e6b06e7UL, 0xfed41b76UL, 0x89d32be0UL, 0x10da7a5aUL, + 0x67dd4accUL, 0xf9b9df6fUL, 0x8ebeeff9UL, 0x17b7be43UL, 0x60b08ed5UL, + 0xd6d6a3e8UL, 0xa1d1937eUL, 0x38d8c2c4UL, 0x4fdff252UL, 0xd1bb67f1UL, + 0xa6bc5767UL, 0x3fb506ddUL, 0x48b2364bUL, 0xd80d2bdaUL, 0xaf0a1b4cUL, + 0x36034af6UL, 0x41047a60UL, 0xdf60efc3UL, 0xa867df55UL, 0x316e8eefUL, + 0x4669be79UL, 0xcb61b38cUL, 0xbc66831aUL, 0x256fd2a0UL, 0x5268e236UL, + 0xcc0c7795UL, 0xbb0b4703UL, 0x220216b9UL, 0x5505262fUL, 0xc5ba3bbeUL, + 0xb2bd0b28UL, 0x2bb45a92UL, 0x5cb36a04UL, 0xc2d7ffa7UL, 0xb5d0cf31UL, + 0x2cd99e8bUL, 0x5bdeae1dUL, 0x9b64c2b0UL, 0xec63f226UL, 0x756aa39cUL, + 0x026d930aUL, 0x9c0906a9UL, 0xeb0e363fUL, 0x72076785UL, 0x05005713UL, + 0x95bf4a82UL, 0xe2b87a14UL, 0x7bb12baeUL, 0x0cb61b38UL, 0x92d28e9bUL, + 0xe5d5be0dUL, 0x7cdcefb7UL, 0x0bdbdf21UL, 0x86d3d2d4UL, 0xf1d4e242UL, + 0x68ddb3f8UL, 0x1fda836eUL, 0x81be16cdUL, 0xf6b9265bUL, 0x6fb077e1UL, + 0x18b74777UL, 0x88085ae6UL, 0xff0f6a70UL, 0x66063bcaUL, 0x11010b5cUL, + 0x8f659effUL, 0xf862ae69UL, 0x616bffd3UL, 0x166ccf45UL, 0xa00ae278UL, + 0xd70dd2eeUL, 0x4e048354UL, 0x3903b3c2UL, 0xa7672661UL, 0xd06016f7UL, + 0x4969474dUL, 0x3e6e77dbUL, 0xaed16a4aUL, 0xd9d65adcUL, 0x40df0b66UL, + 0x37d83bf0UL, 0xa9bcae53UL, 0xdebb9ec5UL, 0x47b2cf7fUL, 0x30b5ffe9UL, + 0xbdbdf21cUL, 0xcabac28aUL, 0x53b39330UL, 0x24b4a3a6UL, 0xbad03605UL, + 0xcdd70693UL, 0x54de5729UL, 0x23d967bfUL, 0xb3667a2eUL, 0xc4614ab8UL, + 0x5d681b02UL, 0x2a6f2b94UL, 0xb40bbe37UL, 0xc30c8ea1UL, 0x5a05df1bUL, + 0x2d02ef8dL +}; +#endif + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +uLongf *get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif + return (uLongf *)crc_table; +} + +/* ========================================================================= */ +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +/* ========================================================================= */ +PR_PUBLIC_API(uLong) crc32(crc, buf, len) + uLong crc; + const Bytef *buf; + uInt len; +{ + if (buf == Z_NULL) return 0L; +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif + crc = crc ^ 0xffffffffUL; + while (len >= 8) + { + DO8(buf); + len -= 8; + } + if (len) do { + DO1(buf); + } while (--len); + return crc ^ 0xffffffffUL; +} diff --git a/security/nss/cmd/zlib/deflate.c b/security/nss/cmd/zlib/deflate.c new file mode 100644 index 000000000..f748ce156 --- /dev/null +++ b/security/nss/cmd/zlib/deflate.c @@ -0,0 +1,1209 @@ +/* deflate.c -- compress data using the deflation algorithm + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ +/* This file was modified since it was taken from the zlib distribution */ +/* + * ALGORITHM + * + * The "deflation" process depends on being able to identify portions + * of the input text which are identical to earlier input (within a + * sliding window trailing behind the input currently being processed). + * + * The most straightforward technique turns out to be the fastest for + * most input files: try all possible matches and select the longest. + * The key feature of this algorithm is that insertions into the string + * dictionary are very simple and thus fast, and deletions are avoided + * completely. Insertions are performed at each input character, whereas + * string matches are performed only when the previous match ends. So it + * is preferable to spend more time in matches to allow very fast string + * insertions and avoid deletions. The matching algorithm for small + * strings is inspired from that of Rabin & Karp. A brute force approach + * is used to find longer strings when a small match has been found. + * A similar algorithm is used in comic (by Jan-Mark Wams) and freeze + * (by Leonid Broukhis). + * A previous version of this file used a more sophisticated algorithm + * (by Fiala and Greene) which is guaranteed to run in linear amortized + * time, but has a larger average cost, uses more memory and is patented. + * However the F&G algorithm may be faster for some highly redundant + * files if the parameter max_chain_length (described below) is too large. + * + * ACKNOWLEDGEMENTS + * + * The idea of lazy evaluation of matches is due to Jan-Mark Wams, and + * I found it in 'freeze' written by Leonid Broukhis. + * Thanks to many people for bug reports and testing. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * A description of the Rabin and Karp algorithm is given in the book + * "Algorithms" by R. Sedgewick, Addison-Wesley, p252. + * + * Fiala,E.R., and Greene,D.H. + * Data Compression with Finite Windows, Comm.ACM, 32,4 (1989) 490-595 + * + */ + +/* $Id$ */ + +#include "deflate.h" + +char deflate_copyright[] = " deflate 1.0.4 Copyright 1995-1996 Jean-loup Gailly "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* =========================================================================== + * Function prototypes. + */ +typedef enum { + need_more, /* block not completed, need more input or more output */ + block_done, /* block flush performed */ + finish_started, /* finish started, need only more output at next deflate */ + finish_done /* finish done, accept no more input or output */ +} block_state; + +typedef block_state (*compress_func) OF((deflate_state *s, int flush)); +/* Compression function. Returns the block state after the call. */ + +local void fill_window OF((deflate_state *s)); +local block_state deflate_stored OF((deflate_state *s, int flush)); +local block_state deflate_fast OF((deflate_state *s, int flush)); +local block_state deflate_slow OF((deflate_state *s, int flush)); +local void lm_init OF((deflate_state *s)); +local uInt longest_match OF((deflate_state *s, IPos cur_match)); +local void putShortMSB OF((deflate_state *s, uInt b)); +local void flush_pending OF((z_streamp strm)); +local int read_buf OF((z_streamp strm, charf *buf, unsigned size)); +#ifdef ASMV + void match_init OF((void)); /* asm code initialization */ +#endif + +#ifdef DEBUG_NEVER +local void check_match OF((deflate_state *s, IPos start, IPos match, + int length)); +#endif + +/* =========================================================================== + * Local data + */ + +#define NIL 0 +/* Tail of hash chains */ + +#ifndef TOO_FAR +# define TOO_FAR 4096 +#endif +/* Matches of length 3 are discarded if their distance exceeds TOO_FAR */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +/* Values for max_lazy_match, good_match and max_chain_length, depending on + * the desired pack level (0..9). The values given below have been tuned to + * exclude worst case performance for pathological files. Better values may be + * found for specific files. + */ +typedef struct config_s { + ush good_length; /* reduce lazy search above this match length */ + ush max_lazy; /* do not perform lazy search above this match length */ + ush nice_length; /* quit search above this match length */ + ush max_chain; + compress_func func; +} config; + +local config configuration_table[10] = { +/* good lazy nice chain */ +/* 0 */ {0, 0, 0, 0, deflate_stored}, /* store only */ +/* 1 */ {4, 4, 8, 4, deflate_fast}, /* maximum speed, no lazy matches */ +/* 2 */ {4, 5, 16, 8, deflate_fast}, +/* 3 */ {4, 6, 32, 32, deflate_fast}, + +/* 4 */ {4, 4, 16, 16, deflate_slow}, /* lazy matches */ +/* 5 */ {8, 16, 32, 32, deflate_slow}, +/* 6 */ {8, 16, 128, 128, deflate_slow}, +/* 7 */ {8, 32, 128, 256, deflate_slow}, +/* 8 */ {32, 128, 258, 1024, deflate_slow}, +/* 9 */ {32, 258, 258, 4096, deflate_slow}}; /* maximum compression */ + +/* Note: the deflate() code requires max_lazy >= MIN_MATCH and max_chain >= 4 + * For deflate_fast() (levels <= 3) good is ignored and lazy has a different + * meaning. + */ + +#define EQUAL 0 +/* result of memcmp for equal strings */ + +struct static_tree_desc_s {int dummy;}; /* for buggy compilers */ + +/* =========================================================================== + * Update a hash value with the given input byte + * IN assertion: all calls to to UPDATE_HASH are made with consecutive + * input characters, so that a running hash key can be computed from the + * previous key instead of complete recalculation each time. + */ +#define UPDATE_HASH(s,h,c) (h = (((h)<<s->hash_shift) ^ (c)) & s->hash_mask) + + +/* =========================================================================== + * Insert string str in the dictionary and set match_head to the previous head + * of the hash chain (the most recent string with same hash key). Return + * the previous length of the hash chain. + * IN assertion: all calls to to INSERT_STRING are made with consecutive + * input characters and the first MIN_MATCH bytes of str are valid + * (except for the last MIN_MATCH-1 bytes of the input file). + */ +#define INSERT_STRING(s, str, match_head) \ + (UPDATE_HASH(s, s->ins_h, s->window[(str) + (MIN_MATCH-1)]), \ + s->prev[(str) & s->w_mask] = match_head = s->head[s->ins_h], \ + s->head[s->ins_h] = (Pos)(str)) + +/* =========================================================================== + * Initialize the hash table (avoiding 64K overflow for 16 bit systems). + * prev[] will be initialized on the fly. + */ +#define CLEAR_HASH(s) \ + s->head[s->hash_size-1] = NIL; \ + zmemzero((charf *)s->head, (unsigned)(s->hash_size-1)*sizeof(*s->head)); + +/* ========================================================================= */ +PR_PUBLIC_API(int) deflateInit_(strm, level, version, stream_size) + z_streamp strm; + int level; + const char *version; + int stream_size; +{ + return deflateInit2_(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, + Z_DEFAULT_STRATEGY, version, stream_size); + /* To do: ignore strm->next_in if we use it as window */ +} + +/* ========================================================================= */ +PR_PUBLIC_API(int) deflateInit2_(strm, level, method, windowBits, memLevel, strategy, + version, stream_size) + z_streamp strm; + int level; + int method; + int windowBits; + int memLevel; + int strategy; + const char *version; + int stream_size; +{ + deflate_state *s; + int noheader = 0; + + ushf *overlay; + /* We overlay pending_buf and d_buf+l_buf. This works since the average + * output size for (length,distance) codes is <= 24 bits. + */ + + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream)) { + return Z_VERSION_ERROR; + } + if (strm == Z_NULL) return Z_STREAM_ERROR; + + strm->msg = Z_NULL; + if (strm->zalloc == Z_NULL) { + strm->zalloc = zcalloc; + strm->opaque = (voidpf)0; + } + if (strm->zfree == Z_NULL) strm->zfree = zcfree; + + if (level == Z_DEFAULT_COMPRESSION) level = 6; + + if (windowBits < 0) { /* undocumented feature: suppress zlib header */ + noheader = 1; + windowBits = -windowBits; + } + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || + windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + s = (deflate_state *) ZALLOC(strm, 1, sizeof(deflate_state)); + if (s == Z_NULL) return Z_MEM_ERROR; + strm->state = (struct internal_state FAR *)s; + s->strm = strm; + + s->noheader = noheader; + s->w_bits = windowBits; + s->w_size = 1 << s->w_bits; + s->w_mask = s->w_size - 1; + + s->hash_bits = memLevel + 7; + s->hash_size = 1 << s->hash_bits; + s->hash_mask = s->hash_size - 1; + s->hash_shift = ((s->hash_bits+MIN_MATCH-1)/MIN_MATCH); + + s->window = (Bytef *) ZALLOC(strm, s->w_size, 2*sizeof(Byte)); + s->prev = (Posf *) ZALLOC(strm, s->w_size, sizeof(Pos)); + s->head = (Posf *) ZALLOC(strm, s->hash_size, sizeof(Pos)); + + s->lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */ + + overlay = (ushf *) ZALLOC(strm, s->lit_bufsize, sizeof(ush)+2); + s->pending_buf = (uchf *) overlay; + + if (s->window == Z_NULL || s->prev == Z_NULL || s->head == Z_NULL || + s->pending_buf == Z_NULL) { + strm->msg = (char*)ERR_MSG(Z_MEM_ERROR); + deflateEnd (strm); + return Z_MEM_ERROR; + } + s->d_buf = overlay + s->lit_bufsize/sizeof(ush); + s->l_buf = s->pending_buf + (1+sizeof(ush))*s->lit_bufsize; + + s->level = level; + s->strategy = strategy; + s->method = (Byte)method; + + return deflateReset(strm); +} + +/* ========================================================================= */ +PR_PUBLIC_API(int) deflateSetDictionary (strm, dictionary, dictLength) + z_streamp strm; + const Bytef *dictionary; + uInt dictLength; +{ + deflate_state *s; + uInt length = dictLength; + uInt n; + IPos hash_head = 0; + + if (strm == Z_NULL || strm->state == Z_NULL || dictionary == Z_NULL || + strm->state->status != INIT_STATE) return Z_STREAM_ERROR; + + s = strm->state; + strm->adler = adler32(strm->adler, dictionary, dictLength); + + if (length < MIN_MATCH) return Z_OK; + if (length > MAX_DIST(s)) { + length = MAX_DIST(s); + dictionary += dictLength - length; + } + zmemcpy((charf *)s->window, dictionary, length); + s->strstart = length; + s->block_start = (long)length; + + /* Insert all strings in the hash table (except for the last two bytes). + * s->lookahead stays null, so s->ins_h will be recomputed at the next + * call of fill_window. + */ + s->ins_h = s->window[0]; + UPDATE_HASH(s, s->ins_h, s->window[1]); + for (n = 0; n <= length - MIN_MATCH; n++) { + INSERT_STRING(s, n, hash_head); + } + if (hash_head) hash_head = 0; /* to make compiler happy */ + return Z_OK; +} + +/* ========================================================================= */ +PR_PUBLIC_API(int) deflateReset (strm) + z_streamp strm; +{ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + strm->zalloc == Z_NULL || strm->zfree == Z_NULL) return Z_STREAM_ERROR; + + strm->total_in = strm->total_out = 0; + strm->msg = Z_NULL; /* use zfree if we ever allocate msg dynamically */ + strm->data_type = Z_UNKNOWN; + + s = (deflate_state *)strm->state; + s->pending = 0; + s->pending_out = s->pending_buf; + + if (s->noheader < 0) { + s->noheader = 0; /* was set to -1 by deflate(..., Z_FINISH); */ + } + s->status = s->noheader ? BUSY_STATE : INIT_STATE; + strm->adler = 1; + s->last_flush = Z_NO_FLUSH; + + _tr_init(s); + lm_init(s); + + return Z_OK; +} + +/* ========================================================================= */ +PR_PUBLIC_API(int) deflateParams(strm, level, strategy) + z_streamp strm; + int level; + int strategy; +{ + deflate_state *s; + compress_func func; + int err = Z_OK; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + s = strm->state; + + if (level == Z_DEFAULT_COMPRESSION) { + level = 6; + } + if (level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } + func = configuration_table[s->level].func; + + if (func != configuration_table[level].func && strm->total_in != 0) { + /* Flush the last buffer: */ + err = deflate(strm, Z_PARTIAL_FLUSH); + } + if (s->level != level) { + s->level = level; + s->max_lazy_match = configuration_table[level].max_lazy; + s->good_match = configuration_table[level].good_length; + s->nice_match = configuration_table[level].nice_length; + s->max_chain_length = configuration_table[level].max_chain; + } + s->strategy = strategy; + return err; +} + +/* ========================================================================= + * Put a short in the pending buffer. The 16-bit value is put in MSB order. + * IN assertion: the stream state is correct and there is enough room in + * pending_buf. + */ +local void putShortMSB (s, b) + deflate_state *s; + uInt b; +{ + put_byte(s, (Byte)(b >> 8)); + put_byte(s, (Byte)(b & 0xff)); +} + +/* ========================================================================= + * Flush as much pending output as possible. All deflate() output goes + * through this function so some applications may wish to modify it + * to avoid allocating a large strm->next_out buffer and copying into it. + * (See also read_buf()). + */ +local void flush_pending(strm) + z_streamp strm; +{ + unsigned len = strm->state->pending; + + if (len > strm->avail_out) len = strm->avail_out; + if (len == 0) return; + + zmemcpy(strm->next_out, strm->state->pending_out, len); + strm->next_out += len; + strm->state->pending_out += len; + strm->total_out += len; + strm->avail_out -= len; + strm->state->pending -= len; + if (strm->state->pending == 0) { + strm->state->pending_out = strm->state->pending_buf; + } +} + +/* ========================================================================= */ +PR_PUBLIC_API(int) deflate (strm, flush) + z_streamp strm; + int flush; +{ + int old_flush; /* value of flush param for previous deflate call */ + deflate_state *s; + + if (strm == Z_NULL || strm->state == Z_NULL || + flush > Z_FINISH || flush < 0) { + return Z_STREAM_ERROR; + } + s = strm->state; + + if (strm->next_out == Z_NULL || + (strm->next_in == Z_NULL && strm->avail_in != 0) || + (s->status == FINISH_STATE && flush != Z_FINISH)) { + ERR_RETURN(strm, Z_STREAM_ERROR); + } + if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR); + + s->strm = strm; /* just in case */ + old_flush = s->last_flush; + s->last_flush = flush; + + /* Write the zlib header */ + if (s->status == INIT_STATE) { + + uInt header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8; + uInt level_flags = (s->level-1) >> 1; + + if (level_flags > 3) level_flags = 3; + header |= (level_flags << 6); + if (s->strstart != 0) header |= PRESET_DICT; + header += 31 - (header % 31); + + s->status = BUSY_STATE; + putShortMSB(s, header); + + /* Save the adler32 of the preset dictionary: */ + if (s->strstart != 0) { + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + } + strm->adler = 1L; + } + + /* Flush as much pending output as possible */ + if (s->pending != 0) { + flush_pending(strm); + if (strm->avail_out == 0) { + /* Since avail_out is 0, deflate will be called again with + * more output space, but possibly with both pending and + * avail_in equal to zero. There won't be anything to do, + * but this is not an error situation so make sure we + * return OK instead of BUF_ERROR at next call of deflate: + */ + s->last_flush = -1; + return Z_OK; + } + + /* Make sure there is something to do and avoid duplicate consecutive + * flushes. For repeated and useless calls with Z_FINISH, we keep + * returning Z_STREAM_END instead of Z_BUFF_ERROR. + */ + } else if (strm->avail_in == 0 && flush <= old_flush && + flush != Z_FINISH) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* User must not provide more input after the first FINISH: */ + if (s->status == FINISH_STATE && strm->avail_in != 0) { + ERR_RETURN(strm, Z_BUF_ERROR); + } + + /* Start a new block or continue the current one. + */ + if (strm->avail_in != 0 || s->lookahead != 0 || + (flush != Z_NO_FLUSH && s->status != FINISH_STATE)) { + block_state bstate; + + bstate = (*(configuration_table[s->level].func))(s, flush); + + if (bstate == finish_started || bstate == finish_done) { + s->status = FINISH_STATE; + } + if (bstate == need_more || bstate == finish_started) { + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR next call, see above */ + } + return Z_OK; + /* If flush != Z_NO_FLUSH && avail_out == 0, the next call + * of deflate should use the same flush parameter to make sure + * that the flush is complete. So we don't have to output an + * empty block here, this will be done at next call. This also + * ensures that for a very small output buffer, we emit at most + * one empty block. + */ + } + if (bstate == block_done) { + if (flush == Z_PARTIAL_FLUSH) { + _tr_align(s); + } else { /* FULL_FLUSH or SYNC_FLUSH */ + _tr_stored_block(s, (char*)0, 0L, 0); + /* For a full flush, this empty block will be recognized + * as a special marker by inflate_sync(). + */ + if (flush == Z_FULL_FLUSH) { + CLEAR_HASH(s); /* forget history */ + } + } + flush_pending(strm); + if (strm->avail_out == 0) { + s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */ + return Z_OK; + } + } + } + Assert(strm->avail_out > 0, "bug2"); + + if (flush != Z_FINISH) return Z_OK; + if (s->noheader) return Z_STREAM_END; + + /* Write the zlib trailer (adler32) */ + putShortMSB(s, (uInt)(strm->adler >> 16)); + putShortMSB(s, (uInt)(strm->adler & 0xffff)); + flush_pending(strm); + /* If avail_out is zero, the application will call deflate again + * to flush the rest. + */ + s->noheader = -1; /* write the trailer only once! */ + return s->pending != 0 ? Z_OK : Z_STREAM_END; +} + +/* ========================================================================= */ +PR_PUBLIC_API(int) deflateEnd (strm) + z_streamp strm; +{ + int status; + + if (strm == Z_NULL || strm->state == Z_NULL) return Z_STREAM_ERROR; + + /* Deallocate in reverse order of allocations: */ + TRY_FREE(strm, strm->state->pending_buf); + TRY_FREE(strm, strm->state->head); + TRY_FREE(strm, strm->state->prev); + TRY_FREE(strm, strm->state->window); + + status = strm->state->status; + ZFREE(strm, strm->state); + strm->state = Z_NULL; + + return status == BUSY_STATE ? Z_DATA_ERROR : Z_OK; +} + +/* ========================================================================= */ +PR_PUBLIC_API(int) deflateCopy (dest, source) + z_streamp dest; + z_streamp source; +{ + if (source == Z_NULL || dest == Z_NULL || source->state == Z_NULL) { + return Z_STREAM_ERROR; + } + *dest = *source; + return Z_STREAM_ERROR; /* to be implemented */ +#if 0 + dest->state = (struct internal_state FAR *) + (*dest->zalloc)(1, sizeof(deflate_state)); + if (dest->state == Z_NULL) return Z_MEM_ERROR; + + *(dest->state) = *(source->state); + return Z_OK; +#endif +} + +/* =========================================================================== + * Read a new buffer from the current input stream, update the adler32 + * and total number of bytes read. All deflate() input goes through + * this function so some applications may wish to modify it to avoid + * allocating a large strm->next_in buffer and copying from it. + * (See also flush_pending()). + */ +local int read_buf(strm, buf, size) + z_streamp strm; + charf *buf; + unsigned size; +{ + unsigned len = strm->avail_in; + + if (len > size) len = size; + if (len == 0) return 0; + + strm->avail_in -= len; + + if (!strm->state->noheader) { + strm->adler = adler32(strm->adler, strm->next_in, len); + } + zmemcpy(buf, strm->next_in, len); + strm->next_in += len; + strm->total_in += len; + + return (int)len; +} + +/* =========================================================================== + * Initialize the "longest match" routines for a new zlib stream + */ +local void lm_init (s) + deflate_state *s; +{ + s->window_size = (ulg)2L*s->w_size; + + CLEAR_HASH(s); + + /* Set the default configuration parameters: + */ + s->max_lazy_match = configuration_table[s->level].max_lazy; + s->good_match = configuration_table[s->level].good_length; + s->nice_match = configuration_table[s->level].nice_length; + s->max_chain_length = configuration_table[s->level].max_chain; + + s->strstart = 0; + s->block_start = 0L; + s->lookahead = 0; + s->match_length = s->prev_length = MIN_MATCH-1; + s->match_available = 0; + s->ins_h = 0; +#ifdef ASMV + match_init(); /* initialize the asm code */ +#endif +} + +/* =========================================================================== + * Set match_start to the longest match starting at the given string and + * return its length. Matches shorter or equal to prev_length are discarded, + * in which case the result is equal to prev_length and match_start is + * garbage. + * IN assertions: cur_match is the head of the hash chain for the current + * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1 + * OUT assertion: the match length is not greater than s->lookahead. + */ +#ifndef ASMV +/* For 80x86 and 680x0, an optimized version will be provided in match.asm or + * match.S. The code will be functionally equivalent. + */ +local uInt longest_match(s, cur_match) + deflate_state *s; + IPos cur_match; /* current match */ +{ + unsigned chain_length = s->max_chain_length;/* max hash chain length */ + register Bytef *scan = s->window + s->strstart; /* current string */ + register Bytef *match; /* matched string */ + register int len; /* length of current match */ + int best_len = s->prev_length; /* best match length so far */ + int nice_match = s->nice_match; /* stop if match long enough */ + IPos limit = s->strstart > (IPos)MAX_DIST(s) ? + s->strstart - (IPos)MAX_DIST(s) : NIL; + /* Stop when cur_match becomes <= limit. To simplify the code, + * we prevent matches with the string of window index 0. + */ + Posf *prev = s->prev; + uInt wmask = s->w_mask; + +#ifdef UNALIGNED_OK + /* Compare two bytes at a time. Note: this is not always beneficial. + * Try with and without -DUNALIGNED_OK to check. + */ + register Bytef *strend = s->window + s->strstart + MAX_MATCH - 1; + register ush scan_start = *(ushf*)scan; + register ush scan_end = *(ushf*)(scan+best_len-1); +#else + register Bytef *strend = s->window + s->strstart + MAX_MATCH; + register Byte scan_end1 = scan[best_len-1]; + register Byte scan_end = scan[best_len]; +#endif + + /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16. + * It is easy to get rid of this optimization if necessary. + */ + Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever"); + + /* Do not waste too much time if we already have a good match: */ + if (s->prev_length >= s->good_match) { + chain_length >>= 2; + } + /* Do not look for matches beyond the end of the input. This is necessary + * to make deflate deterministic. + */ + if ((uInt)nice_match > s->lookahead) nice_match = s->lookahead; + + Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead"); + + do { + Assert(cur_match < s->strstart, "no future"); + match = s->window + cur_match; + + /* Skip to next match if the match length cannot increase + * or if the match length is less than 2: + */ +#if (defined(UNALIGNED_OK) && MAX_MATCH == 258) + /* This code assumes sizeof(unsigned short) == 2. Do not use + * UNALIGNED_OK if your compiler uses a different size. + */ + if (*(ushf*)(match+best_len-1) != scan_end || + *(ushf*)match != scan_start) continue; + + /* It is not necessary to compare scan[2] and match[2] since they are + * always equal when the other bytes match, given that the hash keys + * are equal and that HASH_BITS >= 8. Compare 2 bytes at a time at + * strstart+3, +5, ... up to strstart+257. We check for insufficient + * lookahead only every 4th comparison; the 128th check will be made + * at strstart+257. If MAX_MATCH-2 is not a multiple of 8, it is + * necessary to put more guard bytes at the end of the window, or + * to check more often for insufficient lookahead. + */ + Assert(scan[2] == match[2], "scan[2]?"); + scan++, match++; + do { + } while (*(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + *(ushf*)(scan+=2) == *(ushf*)(match+=2) && + scan < strend); + /* The funny "do {}" generates better code on most compilers */ + + /* Here, scan <= window+strstart+257 */ + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + if (*scan == *match) scan++; + + len = (MAX_MATCH - 1) - (int)(strend-scan); + scan = strend - (MAX_MATCH-1); + +#else /* UNALIGNED_OK */ + + if (match[best_len] != scan_end || + match[best_len-1] != scan_end1 || + *match != *scan || + *++match != scan[1]) continue; + + /* The check at best_len-1 can be removed because it will be made + * again later. (This heuristic is not always a win.) + * It is not necessary to compare scan[2] and match[2] since they + * are always equal when the other bytes match, given that + * the hash keys are equal and that HASH_BITS >= 8. + */ + scan += 2, match++; + Assert(*scan == *match, "match[2]?"); + + /* We check for insufficient lookahead only every 8th comparison; + * the 256th check will be made at strstart+258. + */ + do { + } while (*++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + *++scan == *++match && *++scan == *++match && + scan < strend); + + Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan"); + + len = MAX_MATCH - (int)(strend - scan); + scan = strend - MAX_MATCH; + +#endif /* UNALIGNED_OK */ + + if (len > best_len) { + s->match_start = cur_match; + best_len = len; + if (len >= nice_match) break; +#ifdef UNALIGNED_OK + scan_end = *(ushf*)(scan+best_len-1); +#else + scan_end1 = scan[best_len-1]; + scan_end = scan[best_len]; +#endif + } + } while ((cur_match = prev[cur_match & wmask]) > limit + && --chain_length != 0); + + if ((uInt)best_len <= s->lookahead) return best_len; + return s->lookahead; +} +#endif /* ASMV */ + +#ifdef DEBUG_NEVER +/* =========================================================================== + * Check that the match at match_start is indeed a match. + */ +local void check_match(s, start, match, length) + deflate_state *s; + IPos start, match; + int length; +{ + /* check that the match is indeed a match */ + if (zmemcmp((charf *)s->window + match, + (charf *)s->window + start, length) != EQUAL) { +#if 0 + fprintf(stderr, " start %u, match %u, length %d\n", + start, match, length); +#endif + do { + fprintf(stderr, "%c%c", s->window[match++], s->window[start++]); + } while (--length != 0); + z_error("invalid match"); + } + if (verbose > 1) { + fprintf(stderr,"\\[%d,%d]", start-match, length); + do { putc(s->window[start++], stderr); } while (--length != 0); + } +} +#else +# define check_match(s, start, match, length) +#endif + +/* =========================================================================== + * Fill the window when the lookahead becomes insufficient. + * Updates strstart and lookahead. + * + * IN assertion: lookahead < MIN_LOOKAHEAD + * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD + * At least one byte has been read, or avail_in == 0; reads are + * performed for at least two bytes (required for the zip translate_eol + * option -- not supported here). + */ +local void fill_window(s) + deflate_state *s; +{ + register unsigned n, m; + register Posf *p; + unsigned more; /* Amount of free space at the end of the window. */ + uInt wsize = s->w_size; + + do { + more = (unsigned)(s->window_size -(ulg)s->lookahead -(ulg)s->strstart); + + /* Deal with !@#$% 64K limit: */ + if (more == 0 && s->strstart == 0 && s->lookahead == 0) { + more = wsize; + + } else if (more == (unsigned)(-1)) { + /* Very unlikely, but possible on 16 bit machine if strstart == 0 + * and lookahead == 1 (input done one byte at time) + */ + more--; + + /* If the window is almost full and there is insufficient lookahead, + * move the upper half to the lower one to make room in the upper half. + */ + } else if (s->strstart >= wsize+MAX_DIST(s)) { + + zmemcpy((charf *)s->window, (charf *)s->window+wsize, + (unsigned)wsize); + s->match_start -= wsize; + s->strstart -= wsize; /* we now have strstart >= MAX_DIST */ + + s->block_start -= (long) wsize; + + /* Slide the hash table (could be avoided with 32 bit values + at the expense of memory usage): + */ + n = s->hash_size; + p = &s->head[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + } while (--n); + + n = wsize; + p = &s->prev[n]; + do { + m = *--p; + *p = (Pos)(m >= wsize ? m-wsize : NIL); + /* If n is not on any hash chain, prev[n] is garbage but + * its value will never be used. + */ + } while (--n); + + more += wsize; + } + if (s->strm->avail_in == 0) return; + + /* If there was no sliding: + * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 && + * more == window_size - lookahead - strstart + * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1) + * => more >= window_size - 2*WSIZE + 2 + * In the BIG_MEM or MMAP case (not yet supported), + * window_size == input_size + MIN_LOOKAHEAD && + * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD. + * Otherwise, window_size == 2*WSIZE so more >= 2. + * If there was sliding, more >= WSIZE. So in all cases, more >= 2. + */ + Assert(more >= 2, "more < 2"); + + n = read_buf(s->strm, (charf *)s->window + s->strstart + s->lookahead, + more); + s->lookahead += n; + + /* Initialize the hash value now that we have some input: */ + if (s->lookahead >= MIN_MATCH) { + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + } + /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage, + * but this is not important since only literal bytes will be emitted. + */ + + } while (s->lookahead < MIN_LOOKAHEAD && s->strm->avail_in != 0); +} + +/* =========================================================================== + * Flush the current block, with given end-of-file flag. + * IN assertion: strstart is set to the end of the current match. + */ +#define FLUSH_BLOCK_ONLY(s, eof) { \ + _tr_flush_block(s, (s->block_start >= 0L ? \ + (charf *)&s->window[(unsigned)s->block_start] : \ + (charf *)Z_NULL), \ + (ulg)((long)s->strstart - s->block_start), \ + (eof)); \ + s->block_start = s->strstart; \ + flush_pending(s->strm); \ + Tracev((stderr,"[FLUSH]")); \ +} + +/* Same but force premature exit if necessary. */ +#define FLUSH_BLOCK(s, eof) { \ + FLUSH_BLOCK_ONLY(s, eof); \ + if (s->strm->avail_out == 0) return (eof) ? finish_started : need_more; \ +} + +/* =========================================================================== + * Copy without compression as much as possible from the input stream, return + * the current block state. + * This function does not insert new strings in the dictionary since + * uncompressible data is probably not useful. This function is used + * only for the level=0 compression option. + * NOTE: this function should be optimized to avoid extra copying. + */ +local block_state deflate_stored(s, flush) + deflate_state *s; + int flush; +{ + for (;;) { + /* Fill the window as much as possible: */ + if (s->lookahead <= 1) { + + Assert(s->strstart < s->w_size+MAX_DIST(s) || + s->block_start >= (long)s->w_size, "slide too late"); + + fill_window(s); + if (s->lookahead == 0 && flush == Z_NO_FLUSH) return need_more; + + if (s->lookahead == 0) break; /* flush the current block */ + } + Assert(s->block_start >= 0L, "block gone"); + + s->strstart += s->lookahead; + s->lookahead = 0; + + /* Stored blocks are limited to 0xffff bytes: */ + if (s->strstart == 0 || s->strstart > 0xfffe) { + /* strstart == 0 is possible when wraparound on 16-bit machine */ + s->lookahead = s->strstart - 0xffff; + s->strstart = 0xffff; + } + + /* Emit a stored block if it is large enough: */ + if (s->strstart - (uInt)s->block_start >= MAX_DIST(s)) { + FLUSH_BLOCK(s, 0); + } + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Compress as much as possible from the input stream, return the current + * block state. + * This function does not perform lazy evaluation of matches and inserts + * new strings in the dictionary only for unmatched strings or for short + * matches. It is used only for the fast compression options. + */ +local block_state deflate_fast(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of the hash chain */ + int bflush; /* set if current block must be flushed */ + + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + * At this point we have always match_length < MIN_MATCH + */ + if (hash_head != NIL && s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } + /* longest_match() sets match_start */ + } + if (s->match_length >= MIN_MATCH) { + check_match(s, s->strstart, s->match_start, s->match_length); + + bflush = _tr_tally(s, s->strstart - s->match_start, + s->match_length - MIN_MATCH); + + s->lookahead -= s->match_length; + + /* Insert new strings in the hash table only if the match length + * is not too large. This saves time but degrades compression. + */ + if (s->match_length <= s->max_insert_length && + s->lookahead >= MIN_MATCH) { + s->match_length--; /* string at strstart already in hash table */ + do { + s->strstart++; + INSERT_STRING(s, s->strstart, hash_head); + /* strstart never exceeds WSIZE-MAX_MATCH, so there are + * always MIN_MATCH bytes ahead. + */ + } while (--s->match_length != 0); + s->strstart++; + } else { + s->strstart += s->match_length; + s->match_length = 0; + s->ins_h = s->window[s->strstart]; + UPDATE_HASH(s, s->ins_h, s->window[s->strstart+1]); +#if MIN_MATCH != 3 + Call UPDATE_HASH() MIN_MATCH-3 more times +#endif + /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not + * matter since it will be recomputed at next deflate call. + */ + } + } else { + /* No match, output a literal byte */ + Tracevv((stderr,"%c", s->window[s->strstart])); + bflush = _tr_tally (s, 0, s->window[s->strstart]); + s->lookahead--; + s->strstart++; + } + if (bflush) FLUSH_BLOCK(s, 0); + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} + +/* =========================================================================== + * Same as above, but achieves better compression. We use a lazy + * evaluation for matches: a match is finally adopted only if there is + * no better match at the next window position. + */ +local block_state deflate_slow(s, flush) + deflate_state *s; + int flush; +{ + IPos hash_head = NIL; /* head of hash chain */ + int bflush; /* set if current block must be flushed */ + + /* Process the input block. */ + for (;;) { + /* Make sure that we always have enough lookahead, except + * at the end of the input file. We need MAX_MATCH bytes + * for the next match, plus MIN_MATCH bytes to insert the + * string following the next match. + */ + if (s->lookahead < MIN_LOOKAHEAD) { + fill_window(s); + if (s->lookahead < MIN_LOOKAHEAD && flush == Z_NO_FLUSH) { + return need_more; + } + if (s->lookahead == 0) break; /* flush the current block */ + } + + /* Insert the string window[strstart .. strstart+2] in the + * dictionary, and set hash_head to the head of the hash chain: + */ + if (s->lookahead >= MIN_MATCH) { + INSERT_STRING(s, s->strstart, hash_head); + } + + /* Find the longest match, discarding those <= prev_length. + */ + s->prev_length = s->match_length, s->prev_match = s->match_start; + s->match_length = MIN_MATCH-1; + + if (hash_head != NIL && s->prev_length < s->max_lazy_match && + s->strstart - hash_head <= MAX_DIST(s)) { + /* To simplify the code, we prevent matches with the string + * of window index 0 (in particular we have to avoid a match + * of the string with itself at the start of the input file). + */ + if (s->strategy != Z_HUFFMAN_ONLY) { + s->match_length = longest_match (s, hash_head); + } + /* longest_match() sets match_start */ + + if (s->match_length <= 5 && (s->strategy == Z_FILTERED || + (s->match_length == MIN_MATCH && + s->strstart - s->match_start > TOO_FAR))) { + + /* If prev_match is also MIN_MATCH, match_start is garbage + * but we will ignore the current match anyway. + */ + s->match_length = MIN_MATCH-1; + } + } + /* If there was a match at the previous step and the current + * match is not better, output the previous match: + */ + if (s->prev_length >= MIN_MATCH && s->match_length <= s->prev_length) { + uInt max_insert = s->strstart + s->lookahead - MIN_MATCH; + /* Do not insert strings in hash table beyond this. */ + + check_match(s, s->strstart-1, s->prev_match, s->prev_length); + + bflush = _tr_tally(s, s->strstart -1 - s->prev_match, + s->prev_length - MIN_MATCH); + + /* Insert in hash table all strings up to the end of the match. + * strstart-1 and strstart are already inserted. If there is not + * enough lookahead, the last two strings are not inserted in + * the hash table. + */ + s->lookahead -= s->prev_length-1; + s->prev_length -= 2; + do { + if (++s->strstart <= max_insert) { + INSERT_STRING(s, s->strstart, hash_head); + } + } while (--s->prev_length != 0); + s->match_available = 0; + s->match_length = MIN_MATCH-1; + s->strstart++; + + if (bflush) FLUSH_BLOCK(s, 0); + + } else if (s->match_available) { + /* If there was no match at the previous position, output a + * single literal. If there was a match but the current match + * is longer, truncate the previous match to a single literal. + */ + Tracevv((stderr,"%c", s->window[s->strstart-1])); + if (_tr_tally (s, 0, s->window[s->strstart-1])) { + FLUSH_BLOCK_ONLY(s, 0); + } + s->strstart++; + s->lookahead--; + if (s->strm->avail_out == 0) return need_more; + } else { + /* There is no previous match to compare with, wait for + * the next step to decide. + */ + s->match_available = 1; + s->strstart++; + s->lookahead--; + } + } + Assert (flush != Z_NO_FLUSH, "no flush?"); + if (s->match_available) { + Tracevv((stderr,"%c", s->window[s->strstart-1])); + _tr_tally (s, 0, s->window[s->strstart-1]); + s->match_available = 0; + } + FLUSH_BLOCK(s, flush == Z_FINISH); + return flush == Z_FINISH ? finish_done : block_done; +} diff --git a/security/nss/cmd/zlib/deflate.h b/security/nss/cmd/zlib/deflate.h new file mode 100644 index 000000000..410b21984 --- /dev/null +++ b/security/nss/cmd/zlib/deflate.h @@ -0,0 +1,275 @@ +/* deflate.h -- internal compression state + * Copyright (C) 1995-1996 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* $Id$ */ + +#ifndef _DEFLATE_H +#define _DEFLATE_H + +#include "zutil.h" + +/* =========================================================================== + * Internal compression state. + */ + +#define LENGTH_CODES 29 +/* number of length codes, not counting the special END_BLOCK code */ + +#define LITERALS 256 +/* number of literal bytes 0..255 */ + +#define L_CODES (LITERALS+1+LENGTH_CODES) +/* number of Literal or Length codes, including the END_BLOCK code */ + +#define D_CODES 30 +/* number of distance codes */ + +#define BL_CODES 19 +/* number of codes used to transfer the bit lengths */ + +#define HEAP_SIZE (2*L_CODES+1) +/* maximum heap size */ + +#define MAX_BITS 15 +/* All codes must not exceed MAX_BITS bits */ + +#define INIT_STATE 42 +#define BUSY_STATE 113 +#define FINISH_STATE 666 +/* Stream status */ + + +/* Data structure describing a single value and its code string. */ +typedef struct ct_data_s { + union { + ush freq; /* frequency count */ + ush code; /* bit string */ + } fc; + union { + ush dad; /* father node in Huffman tree */ + ush len; /* length of bit string */ + } dl; +} FAR ct_data; + +#define Freq fc.freq +#define Code fc.code +#define Dad dl.dad +#define Len dl.len + +typedef struct static_tree_desc_s static_tree_desc; + +typedef struct tree_desc_s { + ct_data *dyn_tree; /* the dynamic tree */ + int max_code; /* largest code with non zero frequency */ + static_tree_desc *stat_desc; /* the corresponding static tree */ +} FAR tree_desc; + +typedef ush Pos; +typedef Pos FAR Posf; +typedef unsigned IPos; + +/* A Pos is an index in the character window. We use short instead of int to + * save space in the various tables. IPos is used only for parameter passing. + */ + +typedef struct internal_state { + z_streamp strm; /* pointer back to this zlib stream */ + int status; /* as the name implies */ + Bytef *pending_buf; /* output still pending */ + Bytef *pending_out; /* next pending byte to output to the stream */ + int pending; /* nb of bytes in the pending buffer */ + int noheader; /* suppress zlib header and adler32 */ + Byte data_type; /* UNKNOWN, BINARY or ASCII */ + Byte method; /* STORED (for zip only) or DEFLATED */ + int last_flush; /* value of flush param for previous deflate call */ + + /* used by deflate.c: */ + + uInt w_size; /* LZ77 window size (32K by default) */ + uInt w_bits; /* log2(w_size) (8..16) */ + uInt w_mask; /* w_size - 1 */ + + Bytef *window; + /* Sliding window. Input bytes are read into the second half of the window, + * and move to the first half later to keep a dictionary of at least wSize + * bytes. With this organization, matches are limited to a distance of + * wSize-MAX_MATCH bytes, but this ensures that IO is always + * performed with a length multiple of the block size. Also, it limits + * the window size to 64K, which is quite useful on MSDOS. + * To do: use the user input buffer as sliding window. + */ + + ulg window_size; + /* Actual size of window: 2*wSize, except when the user input buffer + * is directly used as sliding window. + */ + + Posf *prev; + /* Link to older string with same hash index. To limit the size of this + * array to 64K, this link is maintained only for the last 32K strings. + * An index in this array is thus a window index modulo 32K. + */ + + Posf *head; /* Heads of the hash chains or NIL. */ + + uInt ins_h; /* hash index of string to be inserted */ + uInt hash_size; /* number of elements in hash table */ + uInt hash_bits; /* log2(hash_size) */ + uInt hash_mask; /* hash_size-1 */ + + uInt hash_shift; + /* Number of bits by which ins_h must be shifted at each input + * step. It must be such that after MIN_MATCH steps, the oldest + * byte no longer takes part in the hash key, that is: + * hash_shift * MIN_MATCH >= hash_bits + */ + + long block_start; + /* Window position at the beginning of the current output block. Gets + * negative when the window is moved backwards. + */ + + uInt match_length; /* length of best match */ + IPos prev_match; /* previous match */ + int match_available; /* set if previous match exists */ + uInt strstart; /* start of string to insert */ + uInt match_start; /* start of matching string */ + uInt lookahead; /* number of valid bytes ahead in window */ + + uInt prev_length; + /* Length of the best match at previous step. Matches not greater than this + * are discarded. This is used in the lazy match evaluation. + */ + + uInt max_chain_length; + /* To speed up deflation, hash chains are never searched beyond this + * length. A higher limit improves compression ratio but degrades the + * speed. + */ + + uInt max_lazy_match; + /* Attempt to find a better match only when the current match is strictly + * smaller than this value. This mechanism is used only for compression + * levels >= 4. + */ +# define max_insert_length max_lazy_match + /* Insert new strings in the hash table only if the match length is not + * greater than this length. This saves time but degrades compression. + * max_insert_length is used only for compression levels <= 3. + */ + + int level; /* compression level (1..9) */ + int strategy; /* favor or force Huffman coding*/ + + uInt good_match; + /* Use a faster search when the previous match is longer than this */ + + int nice_match; /* Stop searching when current match exceeds this */ + + /* used by trees.c: */ + /* Didn't use ct_data typedef below to supress compiler warning */ + struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */ + struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */ + struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */ + + struct tree_desc_s l_desc; /* desc. for literal tree */ + struct tree_desc_s d_desc; /* desc. for distance tree */ + struct tree_desc_s bl_desc; /* desc. for bit length tree */ + + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */ + int heap_len; /* number of elements in the heap */ + int heap_max; /* element of largest frequency */ + /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used. + * The same heap array is used to build all trees. + */ + + uch depth[2*L_CODES+1]; + /* Depth of each subtree used as tie breaker for trees of equal frequency + */ + + uchf *l_buf; /* buffer for literals or lengths */ + + uInt lit_bufsize; + /* Size of match buffer for literals/lengths. There are 4 reasons for + * limiting lit_bufsize to 64K: + * - frequencies can be kept in 16 bit counters + * - if compression is not successful for the first block, all input + * data is still in the window so we can still emit a stored block even + * when input comes from standard input. (This can also be done for + * all blocks if lit_bufsize is not greater than 32K.) + * - if compression is not successful for a file smaller than 64K, we can + * even emit a stored file instead of a stored block (saving 5 bytes). + * This is applicable only for zip (not gzip or zlib). + * - creating new Huffman trees less frequently may not provide fast + * adaptation to changes in the input data statistics. (Take for + * example a binary file with poorly compressible code followed by + * a highly compressible string table.) Smaller buffer sizes give + * fast adaptation but have of course the overhead of transmitting + * trees more frequently. + * - I can't count above 4 + */ + + uInt last_lit; /* running index in l_buf */ + + ushf *d_buf; + /* Buffer for distances. To simplify the code, d_buf and l_buf have + * the same number of elements. To use different lengths, an extra flag + * array would be necessary. + */ + + ulg opt_len; /* bit length of current block with optimal trees */ + ulg static_len; /* bit length of current block with static trees */ + ulg compressed_len; /* total bit length of compressed file */ + uInt matches; /* number of string matches in current block */ + int last_eob_len; /* bit length of EOB code for last block */ + +#ifdef DEBUG + ulg bits_sent; /* bit length of the compressed data */ +#endif + + ush bi_buf; + /* Output buffer. bits are inserted starting at the bottom (least + * significant bits). + */ + int bi_valid; + /* Number of valid bits in bi_buf. All bits above the last valid bit + * are always zero. + */ + +} FAR deflate_state; + +/* Output a byte on the stream. + * IN assertion: there is enough room in pending_buf. + */ +#define put_byte(s, c) {s->pending_buf[s->pending++] = (c);} + + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST(s) ((s)->w_size-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + + /* in trees.c */ +void _tr_init OF((deflate_state *s)); +int _tr_tally OF((deflate_state *s, unsigned dist, unsigned lc)); +ulg _tr_flush_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +void _tr_align OF((deflate_state *s)); +void _tr_stored_block OF((deflate_state *s, charf *buf, ulg stored_len, + int eof)); +#endif diff --git a/security/nss/cmd/zlib/example.c b/security/nss/cmd/zlib/example.c new file mode 100644 index 000000000..7c9176094 --- /dev/null +++ b/security/nss/cmd/zlib/example.c @@ -0,0 +1,503 @@ +/* example.c -- usage example of the zlib compression library + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* $Id$ */ + +#include <stdio.h> +#include "zlib.h" + +#ifdef STDC +# include <string.h> +# include <stdlib.h> +#else + extern void exit OF((int)); +#endif + +#define CHECK_ERR(err, msg) { \ + if (err != Z_OK) { \ + fprintf(stderr, "%s error: %d\n", msg, err); \ + exit(1); \ + } \ +} + +const char hello[] = "hello, hello!"; +/* "hello world" would be more standard, but the repeated "hello" + * stresses the compression code better, sorry... + */ + +const char dictionary[] = "hello"; +uLong dictId; /* Adler32 value of the dictionary */ + +void test_compress OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_gzio OF((const char *out, const char *in, + Byte *uncompr, int uncomprLen)); +void test_deflate OF((Byte *compr, uLong comprLen)); +void test_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_deflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_large_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_flush OF((Byte *compr, uLong comprLen)); +void test_sync OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +void test_dict_deflate OF((Byte *compr, uLong comprLen)); +void test_dict_inflate OF((Byte *compr, uLong comprLen, + Byte *uncompr, uLong uncomprLen)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Test compress() and uncompress() + */ +void test_compress(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + uLong len = strlen(hello)+1; + + err = compress(compr, &comprLen, (const Bytef*)hello, len); + CHECK_ERR(err, "compress"); + + strcpy((char*)uncompr, "garbage"); + + err = uncompress(uncompr, &uncomprLen, compr, comprLen); + CHECK_ERR(err, "uncompress"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad uncompress\n"); + } else { + printf("uncompress(): %s\n", uncompr); + } +} + +/* =========================================================================== + * Test read/write of .gz files + */ +void test_gzio(out, in, uncompr, uncomprLen) + const char *out; /* output file */ + const char *in; /* input file */ + Byte *uncompr; + int uncomprLen; +{ + int err; + int len = strlen(hello)+1; + gzFile file; + + file = gzopen(out, "wb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + exit(1); + } + + if (gzwrite(file, (const voidp)hello, (unsigned)len) != len) { + fprintf(stderr, "gzwrite err: %s\n", gzerror(file, &err)); + } + gzclose(file); + + file = gzopen(in, "rb"); + if (file == NULL) { + fprintf(stderr, "gzopen error\n"); + } + strcpy((char*)uncompr, "garbage"); + + uncomprLen = gzread(file, uncompr, (unsigned)uncomprLen); + if (uncomprLen != len) { + fprintf(stderr, "gzread err: %s\n", gzerror(file, &err)); + } + gzclose(file); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad gzread\n"); + } else { + printf("gzread(): %s\n", uncompr); + } +} + +/* =========================================================================== + * Test deflate() with small buffers + */ +void test_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + int len = strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + + while (c_stream.total_in != (uLong)len && c_stream.total_out < comprLen) { + c_stream.avail_in = c_stream.avail_out = 1; /* force small buffers */ + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + } + /* Finish the stream, still forcing small buffers: */ + for (;;) { + c_stream.avail_out = 1; + err = deflate(&c_stream, Z_FINISH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "deflate"); + } + + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with small buffers + */ +void test_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_in = compr; + d_stream.next_out = uncompr; + + while (d_stream.total_out < uncomprLen && d_stream.total_in < comprLen) { + d_stream.avail_in = d_stream.avail_out = 1; /* force small buffers */ + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate\n"); + } else { + printf("inflate(): %s\n", uncompr); + } +} + +/* =========================================================================== + * Test deflate() with large buffers and dynamic change of compression level + */ +void test_large_deflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_SPEED); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + /* At this point, uncompr is still mostly zeroes, so it should compress + * very well: + */ + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + if (c_stream.avail_in != 0) { + fprintf(stderr, "deflate not greedy\n"); + } + + /* Feed in already compressed data and switch to no compression: */ + deflateParams(&c_stream, Z_NO_COMPRESSION, Z_DEFAULT_STRATEGY); + c_stream.next_in = compr; + c_stream.avail_in = (uInt)comprLen/2; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + /* Switch back to compressing mode: */ + deflateParams(&c_stream, Z_BEST_COMPRESSION, Z_FILTERED); + c_stream.next_in = uncompr; + c_stream.avail_in = (uInt)uncomprLen; + err = deflate(&c_stream, Z_NO_FLUSH); + CHECK_ERR(err, "deflate"); + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with large buffers + */ +void test_large_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + for (;;) { + d_stream.next_out = uncompr; /* discard the output */ + d_stream.avail_out = (uInt)uncomprLen; + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + CHECK_ERR(err, "large inflate"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (d_stream.total_out != 2*uncomprLen + comprLen/2) { + fprintf(stderr, "bad large inflate: %ld\n", d_stream.total_out); + } else { + printf("large_inflate(): OK\n"); + } +} + +/* =========================================================================== + * Test deflate() with full flush + */ +void test_flush(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + int len = strlen(hello)+1; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_DEFAULT_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + c_stream.next_in = (Bytef*)hello; + c_stream.next_out = compr; + c_stream.avail_in = 3; + c_stream.avail_out = (uInt)comprLen; + err = deflate(&c_stream, Z_FULL_FLUSH); + CHECK_ERR(err, "deflate"); + + compr[3]++; /* force an error in first compressed block */ + c_stream.avail_in = len - 3; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + CHECK_ERR(err, "deflate"); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflateSync() + */ +void test_sync(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_in = compr; + d_stream.next_out = uncompr; + d_stream.avail_in = 2; /* just read the zlib header */ + d_stream.avail_out = (uInt)uncomprLen; + + inflate(&d_stream, Z_NO_FLUSH); + CHECK_ERR(err, "inflate"); + + d_stream.avail_in = (uInt)comprLen-2; /* read all compressed data */ + err = inflateSync(&d_stream); /* but skip the damaged part */ + CHECK_ERR(err, "inflateSync"); + + err = inflate(&d_stream, Z_FINISH); + if (err != Z_DATA_ERROR) { + fprintf(stderr, "inflate should report DATA_ERROR\n"); + /* Because of incorrect adler32 */ + } + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + printf("after inflateSync(): hel%s\n", uncompr); +} + +/* =========================================================================== + * Test deflate() with preset dictionary + */ +void test_dict_deflate(compr, comprLen) + Byte *compr; + uLong comprLen; +{ + z_stream c_stream; /* compression stream */ + int err; + + c_stream.zalloc = (alloc_func)0; + c_stream.zfree = (free_func)0; + c_stream.opaque = (voidpf)0; + + err = deflateInit(&c_stream, Z_BEST_COMPRESSION); + CHECK_ERR(err, "deflateInit"); + + err = deflateSetDictionary(&c_stream, + (const Bytef*)dictionary, sizeof(dictionary)); + CHECK_ERR(err, "deflateSetDictionary"); + + dictId = c_stream.adler; + c_stream.next_out = compr; + c_stream.avail_out = (uInt)comprLen; + + c_stream.next_in = (Bytef*)hello; + c_stream.avail_in = (uInt)strlen(hello)+1; + + err = deflate(&c_stream, Z_FINISH); + if (err != Z_STREAM_END) { + fprintf(stderr, "deflate should report Z_STREAM_END\n"); + } + err = deflateEnd(&c_stream); + CHECK_ERR(err, "deflateEnd"); +} + +/* =========================================================================== + * Test inflate() with a preset dictionary + */ +void test_dict_inflate(compr, comprLen, uncompr, uncomprLen) + Byte *compr, *uncompr; + uLong comprLen, uncomprLen; +{ + int err; + z_stream d_stream; /* decompression stream */ + + strcpy((char*)uncompr, "garbage"); + + d_stream.zalloc = (alloc_func)0; + d_stream.zfree = (free_func)0; + d_stream.opaque = (voidpf)0; + + err = inflateInit(&d_stream); + CHECK_ERR(err, "inflateInit"); + + d_stream.next_in = compr; + d_stream.avail_in = (uInt)comprLen; + + d_stream.next_out = uncompr; + d_stream.avail_out = (uInt)uncomprLen; + + for (;;) { + err = inflate(&d_stream, Z_NO_FLUSH); + if (err == Z_STREAM_END) break; + if (err == Z_NEED_DICT) { + if (d_stream.adler != dictId) { + fprintf(stderr, "unexpected dictionary"); + exit(1); + } + err = inflateSetDictionary(&d_stream, (const Bytef*)dictionary, + sizeof(dictionary)); + } + CHECK_ERR(err, "inflate with dict"); + } + + err = inflateEnd(&d_stream); + CHECK_ERR(err, "inflateEnd"); + + if (strcmp((char*)uncompr, hello)) { + fprintf(stderr, "bad inflate with dict\n"); + } else { + printf("inflate with dictionary: %s\n", uncompr); + } +} + +/* =========================================================================== + * Usage: example [output.gz [input.gz]] + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + Byte *compr, *uncompr; + uLong comprLen = 10000*sizeof(int); /* don't overflow on MSDOS */ + uLong uncomprLen = comprLen; + + if (zlibVersion()[0] != ZLIB_VERSION[0]) { + fprintf(stderr, "incompatible zlib version\n"); + exit(1); + + } else if (strcmp(zlibVersion(), ZLIB_VERSION) != 0) { + fprintf(stderr, "warning: different zlib version\n"); + } + + compr = (Byte*)calloc((uInt)comprLen, 1); + uncompr = (Byte*)calloc((uInt)uncomprLen, 1); + /* compr and uncompr are cleared to avoid reading uninitialized + * data and to ensure that uncompr compresses well. + */ + if (compr == Z_NULL || uncompr == Z_NULL) { + printf("out of memory\n"); + exit(1); + } + + test_compress(compr, comprLen, uncompr, uncomprLen); + + test_gzio((argc > 1 ? argv[1] : "foo.gz"), + (argc > 2 ? argv[2] : "foo.gz"), + uncompr, (int)uncomprLen); + + test_deflate(compr, comprLen); + test_inflate(compr, comprLen, uncompr, uncomprLen); + + test_large_deflate(compr, comprLen, uncompr, uncomprLen); + test_large_inflate(compr, comprLen, uncompr, uncomprLen); + + test_flush(compr, comprLen); + test_sync(compr, comprLen, uncompr, uncomprLen); + + test_dict_deflate(compr, comprLen); + test_dict_inflate(compr, comprLen, uncompr, uncomprLen); + + exit(0); + return 0; /* to avoid warning */ +} diff --git a/security/nss/cmd/zlib/gzio.c b/security/nss/cmd/zlib/gzio.c new file mode 100644 index 000000000..c52d30d30 --- /dev/null +++ b/security/nss/cmd/zlib/gzio.c @@ -0,0 +1,537 @@ +/* gzio.c -- IO on .gz files + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ +/* This file was modified since it was taken from the zlib distribution */ + +/* $Id$ */ + +#include <stdio.h> + +#include "zutil.h" + +struct internal_state {int dummy;}; /* for buggy compilers */ + +#define Z_BUFSIZE 4096 + +#define ALLOC(size) malloc(size) +#define TRYFREE(p) {if (p) free(p);} + +static int gz_magic[2] = {0x1f, 0x8b}; /* gzip magic header */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define RESERVED 0xE0 /* bits 5..7: reserved */ + +typedef struct gz_stream { + z_stream stream; + int z_err; /* error code for last stream operation */ + int z_eof; /* set if end of input file */ + FILE *file; /* .gz file */ + Byte *inbuf; /* input buffer */ + Byte *outbuf; /* output buffer */ + uLong crc; /* crc32 of uncompressed data */ + char *msg; /* error message */ + char *path; /* path name for debugging only */ + int transparent; /* 1 if input file is not a .gz file */ + char mode; /* 'w' or 'r' */ +} gz_stream; + + +local gzFile gz_open OF((const char *path, const char *mode, int fd)); +local int get_byte OF((gz_stream *s)); +local void check_header OF((gz_stream *s)); +local int destroy OF((gz_stream *s)); +local void putLong OF((FILE *file, uLong x)); +local uLong getLong OF((gz_stream *s)); + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb"). The file is given either by file descriptor + or path name (if fd == -1). + gz_open return NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ +local gzFile gz_open (path, mode, fd) + const char *path; + const char *mode; + int fd; +{ + int err; + int level = Z_DEFAULT_COMPRESSION; /* compression level */ + char *p = (char*)mode; + gz_stream *s; + char fmode[80]; /* copy of mode, without the compression level */ + char *m = fmode; + + if (!path || !mode) return Z_NULL; + + s = (gz_stream *)ALLOC(sizeof(gz_stream)); + if (!s) return Z_NULL; + + s->stream.zalloc = (alloc_func)0; + s->stream.zfree = (free_func)0; + s->stream.opaque = (voidpf)0; + s->stream.next_in = s->inbuf = Z_NULL; + s->stream.next_out = s->outbuf = Z_NULL; + s->stream.avail_in = s->stream.avail_out = 0; + s->file = NULL; + s->z_err = Z_OK; + s->z_eof = 0; + s->crc = crc32(0L, Z_NULL, 0); + s->msg = NULL; + s->transparent = 0; + + s->path = (char*)ALLOC(strlen(path)+1); + if (s->path == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + strcpy(s->path, path); /* do this early for debugging */ + + s->mode = '\0'; + do { + if (*p == 'r') s->mode = 'r'; + if (*p == 'w' || *p == 'a') s->mode = 'w'; + if (*p >= '0' && *p <= '9') { + level = *p - '0'; + } else { + *m++ = *p; /* copy the mode */ + } + } while (*p++ && m != fmode + sizeof(fmode)); + if (s->mode == '\0') return destroy(s), (gzFile)Z_NULL; + + if (s->mode == 'w') { + err = deflateInit2(&(s->stream), level, + Z_DEFLATED, -MAX_WBITS, DEF_MEM_LEVEL, 0); + /* windowBits is passed < 0 to suppress zlib header */ + + s->stream.next_out = s->outbuf = (Byte*)ALLOC(Z_BUFSIZE); + + if (err != Z_OK || s->outbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } else { + err = inflateInit2(&(s->stream), -MAX_WBITS); + s->stream.next_in = s->inbuf = (Byte*)ALLOC(Z_BUFSIZE); + + if (err != Z_OK || s->inbuf == Z_NULL) { + return destroy(s), (gzFile)Z_NULL; + } + } + s->stream.avail_out = Z_BUFSIZE; + + errno = 0; + s->file = fd < 0 ? FOPEN(path, fmode) : (FILE*)fdopen(fd, fmode); + + if (s->file == NULL) { + return destroy(s), (gzFile)Z_NULL; + } + if (s->mode == 'w') { + /* Write a very simple .gz header: + */ + fprintf(s->file, "%c%c%c%c%c%c%c%c%c%c", gz_magic[0], gz_magic[1], + Z_DEFLATED, 0 /*flags*/, 0,0,0,0 /*time*/, 0 /*xflags*/, OS_CODE); + } else { + check_header(s); /* skip the .gz header */ + } + return (gzFile)s; +} + +/* =========================================================================== + Opens a gzip (.gz) file for reading or writing. +*/ +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern gzFile) gzopen (const char *path, const char *mode) +#else +extern gzFile EXPORT gzopen OF((const char *path, const char *mode)) +#endif +{ + return gz_open (path, mode, -1); +} + +/* =========================================================================== + Associate a gzFile with the file descriptor fd. fd is not dup'ed here + to mimic the behavio(u)r of fdopen. +*/ +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern gzFile) gzdopen (int fd, const char *mode) +#else +extern gzFile EXPORT gzdopen OF((int fd, const char *mode)) +#endif +{ + char name[20]; + + if (fd < 0) return (gzFile)Z_NULL; + sprintf(name, "<fd:%d>", fd); /* for debugging */ + + return gz_open (name, mode, fd); +} + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ +local int get_byte(s) + gz_stream *s; +{ + if (s->z_eof) return EOF; + if (s->stream.avail_in == 0) { + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) s->z_err = Z_ERRNO; + return EOF; + } + s->stream.next_in = s->inbuf; + } + s->stream.avail_in--; + return *(s->stream.next_in)++; +} + +/* =========================================================================== + Check the gzip header of a gz_stream opened for reading. Set the stream + mode to transparent if the gzip magic header is not present; set s->err + to Z_DATA_ERROR if the magic header is present but the rest of the header + is incorrect. + IN assertion: the stream s has already been created sucessfully; + s->stream.avail_in is zero for the first time, but may be non-zero + for concatenated .gz files. +*/ +local void check_header(s) + gz_stream *s; +{ + int method; /* method byte */ + int flags; /* flags byte */ + uInt len; + int c; + + /* Check the gzip magic header */ + for (len = 0; len < 2; len++) { + c = get_byte(s); + if (c != gz_magic[len]) { + s->transparent = 1; + if (c != EOF) s->stream.avail_in++, s->stream.next_in--; + s->z_err = s->stream.avail_in != 0 ? Z_OK : Z_STREAM_END; + return; + } + } + method = get_byte(s); + flags = get_byte(s); + if (method != Z_DEFLATED || (flags & RESERVED) != 0) { + s->z_err = Z_DATA_ERROR; + return; + } + + /* Discard time, xflags and OS code: */ + for (len = 0; len < 6; len++) (void)get_byte(s); + + if ((flags & EXTRA_FIELD) != 0) { /* skip the extra field */ + len = (uInt)get_byte(s); + len += ((uInt)get_byte(s))<<8; + /* len is garbage if EOF but the loop below will quit anyway */ + while (len-- != 0 && get_byte(s) != EOF) ; + } + if ((flags & ORIG_NAME) != 0) { /* skip the original file name */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & COMMENT) != 0) { /* skip the .gz file comment */ + while ((c = get_byte(s)) != 0 && c != EOF) ; + } + if ((flags & HEAD_CRC) != 0) { /* skip the header crc */ + for (len = 0; len < 2; len++) (void)get_byte(s); + } + s->z_err = s->z_eof ? Z_DATA_ERROR : Z_OK; +} + + /* =========================================================================== + * Cleanup then free the given gz_stream. Return a zlib error code. + Try freeing in the reverse order of allocations. + */ +local int destroy (s) + gz_stream *s; +{ + int err = Z_OK; + + if (!s) return Z_STREAM_ERROR; + + TRYFREE(s->msg); + + if (s->stream.state != NULL) { + if (s->mode == 'w') { + err = deflateEnd(&(s->stream)); + } else if (s->mode == 'r') { + err = inflateEnd(&(s->stream)); + } + } + if (s->file != NULL && fclose(s->file)) { + err = Z_ERRNO; + } + if (s->z_err < 0) err = s->z_err; + + TRYFREE(s->inbuf); + TRYFREE(s->outbuf); + TRYFREE(s->path); + TRYFREE(s); + return err; +} + +/* =========================================================================== + Reads the given number of uncompressed bytes from the compressed file. + gzread returns the number of bytes actually read (0 for end of file). +*/ +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) gzread (gzFile file, voidp buf, unsigned len) +#else +extern int EXPORT gzread OF((gzFile file, voidp buf, unsigned len)) +#endif +{ + gz_stream *s = (gz_stream*)file; + Bytef *start = buf; /* starting point for crc computation */ + Byte *next_out; /* == stream.next_out but not forced far (for MSDOS) */ + + if (s == NULL || s->mode != 'r') return Z_STREAM_ERROR; + + if (s->z_err == Z_DATA_ERROR || s->z_err == Z_ERRNO) return -1; + if (s->z_err == Z_STREAM_END) return 0; /* EOF */ + + s->stream.next_out = next_out = buf; + s->stream.avail_out = len; + + while (s->stream.avail_out != 0) { + + if (s->transparent) { + /* Copy first the lookahead bytes: */ + uInt n = s->stream.avail_in; + if (n > s->stream.avail_out) n = s->stream.avail_out; + if (n > 0) { + zmemcpy(s->stream.next_out, s->stream.next_in, n); + next_out += n; + s->stream.next_out = next_out; + s->stream.next_in += n; + s->stream.avail_out -= n; + s->stream.avail_in -= n; + } + if (s->stream.avail_out > 0) { + s->stream.avail_out -= fread(next_out, 1, s->stream.avail_out, + s->file); + } + return (int)(len - s->stream.avail_out); + } + if (s->stream.avail_in == 0 && !s->z_eof) { + + errno = 0; + s->stream.avail_in = fread(s->inbuf, 1, Z_BUFSIZE, s->file); + if (s->stream.avail_in == 0) { + s->z_eof = 1; + if (ferror(s->file)) { + s->z_err = Z_ERRNO; + break; + } + } + s->stream.next_in = s->inbuf; + } + s->z_err = inflate(&(s->stream), Z_NO_FLUSH); + + if (s->z_err == Z_STREAM_END) { + /* Check CRC and original size */ + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + start = s->stream.next_out; + + if (getLong(s) != s->crc || getLong(s) != s->stream.total_out) { + s->z_err = Z_DATA_ERROR; + } else { + /* Check for concatenated .gz files: */ + check_header(s); + if (s->z_err == Z_OK) { + inflateReset(&(s->stream)); + s->crc = crc32(0L, Z_NULL, 0); + } + } + } + if (s->z_err != Z_OK || s->z_eof) break; + } + s->crc = crc32(s->crc, start, (uInt)(s->stream.next_out - start)); + + return (int)(len - s->stream.avail_out); +} + +/* =========================================================================== + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of bytes actually written (0 in case of error). +*/ +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) gzwrite (gzFile file, const voidp buf, unsigned len) +#else +extern int EXPORT gzwrite OF((gzFile file, const voidp buf, unsigned len)) +#endif +{ + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.next_in = buf; + s->stream.avail_in = len; + + while (s->stream.avail_in != 0) { + + if (s->stream.avail_out == 0) { + + s->stream.next_out = s->outbuf; + if (fwrite(s->outbuf, 1, Z_BUFSIZE, s->file) != Z_BUFSIZE) { + s->z_err = Z_ERRNO; + break; + } + s->stream.avail_out = Z_BUFSIZE; + } + s->z_err = deflate(&(s->stream), Z_NO_FLUSH); + if (s->z_err != Z_OK) break; + } + s->crc = crc32(s->crc, buf, len); + + return (int)(len - s->stream.avail_in); +} + +/* =========================================================================== + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) gzflush (gzFile file, int flush) +#else +extern int EXPORT gzflush OF((gzFile file, int flush)) +#endif +{ + uInt len; + int done = 0; + gz_stream *s = (gz_stream*)file; + + if (s == NULL || s->mode != 'w') return Z_STREAM_ERROR; + + s->stream.avail_in = 0; /* should be zero already anyway */ + + for (;;) { + len = Z_BUFSIZE - s->stream.avail_out; + + if (len != 0) { + if ((uInt)fwrite(s->outbuf, 1, len, s->file) != len) { + s->z_err = Z_ERRNO; + return Z_ERRNO; + } + s->stream.next_out = s->outbuf; + s->stream.avail_out = Z_BUFSIZE; + } + if (done) break; + s->z_err = deflate(&(s->stream), flush); + + /* deflate has finished flushing only when it hasn't used up + * all the available space in the output buffer: + */ + done = (s->stream.avail_out != 0 || s->z_err == Z_STREAM_END); + + if (s->z_err != Z_OK && s->z_err != Z_STREAM_END) break; + } + fflush(s->file); + return s->z_err == Z_STREAM_END ? Z_OK : s->z_err; +} + +/* =========================================================================== + Outputs a long in LSB order to the given file +*/ +local void putLong (file, x) + FILE *file; + uLong x; +{ + int n; + for (n = 0; n < 4; n++) { + fputc((int)(x & 0xff), file); + x >>= 8; + } +} + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +local uLong getLong (s) + gz_stream *s; +{ + uLong x = (uLong)get_byte(s); + int c; + + x += ((uLong)get_byte(s))<<8; + x += ((uLong)get_byte(s))<<16; + c = get_byte(s); + if (c == EOF) s->z_err = Z_DATA_ERROR; + x += ((uLong)c)<<24; + return x; +} + +/* =========================================================================== + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. +*/ +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) gzclose (gzFile file) +#else +extern int EXPORT gzclose OF((gzFile file)) +#endif +{ + int err; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) return Z_STREAM_ERROR; + + if (s->mode == 'w') { + err = gzflush (file, Z_FINISH); + if (err != Z_OK) return destroy(file); + + putLong (s->file, s->crc); + putLong (s->file, s->stream.total_in); + + } + return destroy(file); +} + +/* =========================================================================== + Returns the error message for the last error which occured on the + given compressed file. errnum is set to zlib error number. If an + error occured in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern const char *) gzerror (gzFile file, int *errnum) +#else +extern const char * EXPORT gzerror OF((gzFile file, int *errnum)) +#endif +{ + char *m; + gz_stream *s = (gz_stream*)file; + + if (s == NULL) { + *errnum = Z_STREAM_ERROR; + return (const char*)ERR_MSG(Z_STREAM_ERROR); + } + *errnum = s->z_err; + if (*errnum == Z_OK) return (const char*)""; + + m = (char*)(*errnum == Z_ERRNO ? zstrerror(errno) : s->stream.msg); + + if (m == NULL || *m == '\0') m = (char*)ERR_MSG(s->z_err); + + TRYFREE(s->msg); + s->msg = (char*)ALLOC(strlen(s->path) + strlen(m) + 3); + strcpy(s->msg, s->path); + strcat(s->msg, ": "); + strcat(s->msg, m); + return (const char*)s->msg; +} diff --git a/security/nss/cmd/zlib/infblock.c b/security/nss/cmd/zlib/infblock.c new file mode 100644 index 000000000..8eddbafed --- /dev/null +++ b/security/nss/cmd/zlib/infblock.c @@ -0,0 +1,406 @@ +/* infblock.c -- interpret and process block types to last block + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ +/* This file was modified since it was taken from the zlib distribution */ + +#include "zutil.h" +#include "infblock.h" +#include "inftrees.h" +#include "infcodes.h" +#include "infutil.h" + +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ + +/* Table for deflate from PKZIP's appnote.txt. */ +local uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +void inflate_blocks_reset(s, z, c) +inflate_blocks_statef *s; +z_streamp z; +uLongf *c; +{ + if (s->checkfn != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == CODES) + { + inflate_codes_free(s->sub.decode.codes, z); + inflate_trees_free(s->sub.decode.td, z); + inflate_trees_free(s->sub.decode.tl, z); + } + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, Z_NULL, 0); + Trace((stderr, "inflate: blocks reset\n")); +} + + +inflate_blocks_statef *inflate_blocks_new(z, c, w) +z_streamp z; +check_func c; +uInt w; +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->window = (Bytef *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Trace((stderr, "inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, &s->check); + return s; +} + + +#ifdef DEBUG + extern uInt inflate_hufts; +#endif +int inflate_blocks(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Trace((stderr, "inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Trace((stderr, "inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.tl = Z_NULL; /* don't try to free these */ + s->sub.decode.td = Z_NULL; + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Trace((stderr, "inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BAD; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = BAD; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev((stderr, "inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev((stderr, "inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BAD; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if (t < 19) + t = 19; + if ((s->sub.trees.blens = (uIntf*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev((stderr, "inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, z); + if (t != Z_OK) + { + ZFREE(z, s->sub.trees.blens); + r = t; + if (r == Z_DATA_ERROR) + s->mode = BAD; + LEAVE + } + s->sub.trees.index = 0; + Tracev((stderr, "inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->word.what.Bits; + c = h->more.Base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + inflate_trees_free(s->sub.trees.tb, z); + ZFREE(z, s->sub.trees.blens); + s->mode = BAD; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + inflate_trees_free(s->sub.trees.tb, z); + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; +#ifdef DEBUG + inflate_hufts = 0; +#endif + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, z); + ZFREE(z, s->sub.trees.blens); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + s->mode = BAD; + r = t; + LEAVE + } + Tracev((stderr, "inflate: trees ok, %d * %d bytes used\n", + inflate_hufts, sizeof(inflate_huft))); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + inflate_trees_free(td, z); + inflate_trees_free(tl, z); + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.codes = c; + s->sub.decode.tl = tl; + s->sub.decode.td = td; + } + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + inflate_trees_free(s->sub.decode.td, z); + inflate_trees_free(s->sub.decode.tl, z); + LOAD + Tracev((stderr, "inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONE; + case DONE: + r = Z_STREAM_END; + LEAVE + case BAD: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +int inflate_blocks_free(s, z, c) +inflate_blocks_statef *s; +z_streamp z; +uLongf *c; +{ + inflate_blocks_reset(s, z, c); + ZFREE(z, s->window); + ZFREE(z, s); + Trace((stderr, "inflate: blocks freed\n")); + return Z_OK; +} + + +void inflate_set_dictionary(s, d, n) +inflate_blocks_statef *s; +const Bytef *d; +uInt n; +{ + zmemcpy((charf *)s->window, d, n); + s->read = s->write = s->window + n; +} diff --git a/security/nss/cmd/zlib/infblock.h b/security/nss/cmd/zlib/infblock.h new file mode 100644 index 000000000..3ecd50cd3 --- /dev/null +++ b/security/nss/cmd/zlib/infblock.h @@ -0,0 +1,37 @@ +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state FAR inflate_blocks_statef; + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLongf *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp , + uLongf *)); /* check value on output */ + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Bytef *d, /* dictionary */ + uInt n)); /* dictionary length */ diff --git a/security/nss/cmd/zlib/infcodes.c b/security/nss/cmd/zlib/infcodes.c new file mode 100644 index 000000000..3ae3818a1 --- /dev/null +++ b/security/nss/cmd/zlib/infcodes.c @@ -0,0 +1,247 @@ +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "infblock.h" +#include "infcodes.h" +#include "infutil.h" +#include "inffast.h" + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ + mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +inflate_codes_statef *inflate_codes_new(bl, bd, tl, td, z) +uInt bl, bd; +inflate_huft *tl; +inflate_huft *td; /* need separate declaration for Borland C++ */ +z_streamp z; +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev((stderr, "inflate: codes new\n")); + } + return c; +} + + +int inflate_codes(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Bytef *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t->next; + break; + } + if (e & 32) /* end of block */ + { + Tracevv((stderr, "inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv((stderr, "inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t->next; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv((stderr, "inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ +#ifndef __TURBOC__ /* Turbo C bug for following expression */ + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; +#else + f = q - c->sub.copy.dist; + if ((uInt)(q - s->window) < c->sub.copy.dist) + f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); +#endif + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +void inflate_codes_free(c, z) +inflate_codes_statef *c; +z_streamp z; +{ + ZFREE(z, c); + Tracev((stderr, "inflate: codes free\n")); +} diff --git a/security/nss/cmd/zlib/infcodes.h b/security/nss/cmd/zlib/infcodes.h new file mode 100644 index 000000000..c2c38df2c --- /dev/null +++ b/security/nss/cmd/zlib/infcodes.h @@ -0,0 +1,27 @@ +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state FAR inflate_codes_statef; + +extern inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_streamp )); + +extern int inflate_codes OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +extern void inflate_codes_free OF(( + inflate_codes_statef *, + z_streamp )); + diff --git a/security/nss/cmd/zlib/inffast.c b/security/nss/cmd/zlib/inffast.c new file mode 100644 index 000000000..86eee4a29 --- /dev/null +++ b/security/nss/cmd/zlib/inffast.c @@ -0,0 +1,168 @@ +/* inffast.c -- process literals and length/distance pairs fast + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "inftrees.h" +#include "infblock.h" +#include "infcodes.h" +#include "infutil.h" +#include "inffast.h" + +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<<k;k+=8;}} +#define UNGRAB {n+=(c=k>>3);p-=c;k&=7;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +int inflate_fast(bl, bd, tl, td, s, z) +uInt bl, bd; +inflate_huft *tl; +inflate_huft *td; /* need separate declaration for Borland C++ */ +inflate_blocks_statef *s; +z_streamp z; +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Bytef *p; /* input data pointer */ + uInt n; /* bytes available there */ + Bytef *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Bytef *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv((stderr, "inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + if ((uInt)(q - s->window) >= d) /* offset before dest */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + } + else /* else offset after destination */ + { + e = d - (uInt)(q - s->window); /* bytes from offset to end */ + r = s->end - e; /* pointer to offset */ + if (c > e) /* if source crosses, */ + { + c -= e; /* copy to end of window */ + do { + *q++ = *r++; + } while (--e); + r = s->window; /* copy rest from start of window */ + } + } + do { /* copy all or what's left */ + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop; + else + { + z->msg = (char*)"invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + if ((e = (t = t->next + ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((stderr, t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv((stderr, "inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = (char*)"invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} diff --git a/security/nss/cmd/zlib/inffast.h b/security/nss/cmd/zlib/inffast.h new file mode 100644 index 000000000..8cc644efb --- /dev/null +++ b/security/nss/cmd/zlib/inffast.h @@ -0,0 +1,17 @@ +/* inffast.h -- header to use inffast.c + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +extern int inflate_fast OF(( + uInt, + uInt, + inflate_huft *, + inflate_huft *, + inflate_blocks_statef *, + z_streamp )); diff --git a/security/nss/cmd/zlib/inffixed.h b/security/nss/cmd/zlib/inffixed.h new file mode 100644 index 000000000..77f7e7631 --- /dev/null +++ b/security/nss/cmd/zlib/inffixed.h @@ -0,0 +1,151 @@ +/* inffixed.h -- table for decoding fixed codes + * Generated automatically by the maketree.c program + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +local uInt fixed_bl = 9; +local uInt fixed_bd = 5; +local inflate_huft fixed_tl[] = { + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} + }; +local inflate_huft fixed_td[] = { + {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, + {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, + {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, + {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, + {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, + {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, + {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, + {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} + }; diff --git a/security/nss/cmd/zlib/inflate.c b/security/nss/cmd/zlib/inflate.c new file mode 100644 index 000000000..8cd0c141c --- /dev/null +++ b/security/nss/cmd/zlib/inflate.c @@ -0,0 +1,346 @@ +/* inflate.c -- zlib interface to inflate modules + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ +/* This file was modified since it was taken from the zlib distribution */ + +#include "zutil.h" +#include "infblock.h" + +struct inflate_blocks_state {int dummy;}; /* for buggy compilers */ + +/* inflate private state */ +struct internal_state { + + /* mode */ + enum { + METHOD, /* waiting for method byte */ + FLAG, /* waiting for flag byte */ + DICT4, /* four dictionary check bytes to go */ + DICT3, /* three dictionary check bytes to go */ + DICT2, /* two dictionary check bytes to go */ + DICT1, /* one dictionary check byte to go */ + DICT0, /* waiting for inflateSetDictionary */ + BLOCKS, /* decompressing blocks */ + CHECK4, /* four check bytes to go */ + CHECK3, /* three check bytes to go */ + CHECK2, /* two check bytes to go */ + CHECK1, /* one check byte to go */ + DONE, /* finished check, done */ + BAD} /* got an error--stay here */ + mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +PR_PUBLIC_API(int) inflateReset(z) +z_streamp z; +{ + uLong c; + + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? BLOCKS : METHOD; + inflate_blocks_reset(z->state->blocks, z, &c); + Trace((stderr, "inflate: reset\n")); + return Z_OK; +} + + +PR_PUBLIC_API(int) inflateEnd(z) +z_streamp z; +{ + uLong c; + + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z, &c); + ZFREE(z, z->state); + z->state = Z_NULL; + Trace((stderr, "inflate: end\n")); + return Z_OK; +} + + +PR_PUBLIC_API(int) inflateInit2_(z, w, version, stream_size) +z_streamp z; +int w; +const char *version; +int stream_size; +{ + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream)) + return Z_VERSION_ERROR; + + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; + z->msg = Z_NULL; + if (z->zalloc == Z_NULL) + { + z->zalloc = zcalloc; + z->opaque = (voidpf)0; + } + if (z->zfree == Z_NULL) z->zfree = zcfree; + if ((z->state = (struct internal_state FAR *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Trace((stderr, "inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + + +PR_PUBLIC_API(int) inflateInit_(z, version, stream_size) +z_streamp z; +const char *version; +int stream_size; +{ + return inflateInit2_(z, DEF_WBITS, version, stream_size); +} + + +#define NEEDBYTE {if(z->avail_in==0)return r;r=Z_OK;} +#define NEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +PR_PUBLIC_API(int) inflate(z, f) +z_streamp z; +int f; +{ + int r; + uInt b; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL || f < 0) + return Z_STREAM_ERROR; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case METHOD: + NEEDBYTE + if (((z->state->sub.method = NEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = BAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = BAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = FLAG; + case FLAG: + NEEDBYTE + b = NEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Trace((stderr, "inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = BLOCKS; + break; + } + z->state->mode = DICT4; + case DICT4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = DICT3; + case DICT3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = DICT2; + case DICT2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = DICT1; + case DICT1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = DICT0; + return Z_NEED_DICT; + case DICT0: + z->state->mode = BAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_STREAM_ERROR; + case BLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (r == Z_DATA_ERROR) + { + z->state->mode = BAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r != Z_STREAM_END) + return r; + r = Z_OK; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = DONE; + break; + } + z->state->mode = CHECK4; + case CHECK4: + NEEDBYTE + z->state->sub.check.need = (uLong)NEXTBYTE << 24; + z->state->mode = CHECK3; + case CHECK3: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 16; + z->state->mode = CHECK2; + case CHECK2: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE << 8; + z->state->mode = CHECK1; + case CHECK1: + NEEDBYTE + z->state->sub.check.need += (uLong)NEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = BAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Trace((stderr, "inflate: zlib check ok\n")); + z->state->mode = DONE; + case DONE: + return Z_STREAM_END; + case BAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } +} + + +PR_PUBLIC_API(int) inflateSetDictionary(z, dictionary, dictLength) +z_streamp z; +const Bytef *dictionary; +uInt dictLength; +{ + uInt length = dictLength; + + if (z == Z_NULL || z->state == Z_NULL || z->state->mode != DICT0) + return Z_STREAM_ERROR; + + if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; + z->adler = 1L; + + if (length >= ((uInt)1<<z->state->wbits)) + { + length = (1<<z->state->wbits)-1; + dictionary += dictLength - length; + } + inflate_set_dictionary(z->state->blocks, dictionary, length); + z->state->mode = BLOCKS; + return Z_OK; +} + + +PR_PUBLIC_API(int) inflateSync(z) +z_streamp z; +{ + uInt n; /* number of bytes to look at */ + Bytef *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != BAD) + { + z->state->mode = BAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + if (*p == (Byte)(m < 2 ? 0 : 0xff)) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += p - z->next_in; + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = BLOCKS; + return Z_OK; +} diff --git a/security/nss/cmd/zlib/inftrees.c b/security/nss/cmd/zlib/inftrees.c new file mode 100644 index 000000000..91dc00375 --- /dev/null +++ b/security/nss/cmd/zlib/inftrees.c @@ -0,0 +1,479 @@ +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ +/* This file was modified since it was taken from the zlib distribution */ + +#include "zutil.h" +#include "inftrees.h" + +char inflate_copyright[] = " inflate 1.0.4 Copyright 1995-1996 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ +struct internal_state {int dummy;}; /* for buggy compilers */ + +/* simplify the use of the inflate_huft type with some defines */ +#define base more.Base +#define next more.Next +#define exop word.what.Exop +#define bits word.what.Bits + + +local int huft_build OF(( + uIntf *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + uIntf *, /* list of base values for non-simple codes */ + uIntf *, /* list of extra bits for non-simple codes */ + inflate_huft * FAR*,/* result: starting table */ + uIntf *, /* maximum lookup bits (returns actual) */ + z_streamp )); /* for zalloc function */ + +local voidpf falloc OF(( + voidpf, /* opaque pointer (not used) */ + uInt, /* number of items */ + uInt)); /* size of item */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +local uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* see note #13 above about 258 */ +local uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ +local uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +local uInt cpdext[30] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ +#define N_MAX 288 /* maximum number of codes in any set */ + +#ifdef DEBUG + uInt inflate_hufts; +#endif + +local int huft_build(b, n, s, d, e, t, m, zs) +uIntf *b; /* code lengths in bits (all assumed <= BMAX) */ +uInt n; /* number of codes (assumed <= N_MAX) */ +uInt s; /* number of simple-valued codes (0..s-1) */ +uIntf *d; /* list of base values for non-simple codes */ +uIntf *e; /* list of extra bits for non-simple codes */ +inflate_huft * FAR *t; /* result: starting table */ +uIntf *m; /* maximum lookup bits, returns actual */ +z_streamp zs; /* for zalloc function */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + set of lengths), or Z_MEM_ERROR if not enough memory. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + register uIntf *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + uInt v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uIntf *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = g - w; + z = z > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + if ((q = (inflate_huft *)ZALLOC + (zs,z + 1,sizeof(inflate_huft))) == Z_NULL) + { + if (h) + inflate_trees_free(u[0], zs); + return Z_MEM_ERROR; /* not enough memory */ + } +#ifdef DEBUG + inflate_hufts += z + 1; +#endif + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->next)) = Z_NULL; + u[h] = ++q; /* table starts after link */ + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + r.next = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h-1][j] = r; /* connect to last table */ + } + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +int inflate_trees_bits(c, bb, tb, z) +uIntf *c; /* 19 code lengths */ +uIntf *bb; /* bits tree desired/actual depth */ +inflate_huft * FAR *tb; /* bits tree result */ +z_streamp z; /* for zfree function */ +{ + int r; + + r = huft_build(c, 19, 19, (uIntf*)Z_NULL, (uIntf*)Z_NULL, tb, bb, z); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + inflate_trees_free(*tb, z); + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + return r; +} + + +int inflate_trees_dynamic(nl, nd, c, bl, bd, tl, td, z) +uInt nl; /* number of literal/length codes */ +uInt nd; /* number of distance codes */ +uIntf *c; /* that many (total) code lengths */ +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +z_streamp z; /* for zfree function */ +{ + int r; + + /* build literal/length tree */ + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, z); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + inflate_trees_free(*tl, z); + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + return r; + } + + /* build distance tree */ + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, z); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + inflate_trees_free(*td, z); + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + inflate_trees_free(*tl, z); + return r; +#endif + } + + /* done */ + return Z_OK; +} + + +/* build fixed tables only once--keep them here */ +local int fixed_built = 0; +#define FIXEDH 530 /* number of hufts used by fixed tables */ +local inflate_huft fixed_mem[FIXEDH]; +local uInt fixed_bl; +local uInt fixed_bd; +local inflate_huft *fixed_tl; +local inflate_huft *fixed_td; + + +local voidpf falloc(q, n, s) +voidpf q; /* opaque pointer */ +uInt n; /* number of items */ +uInt s; /* size of item */ +{ + Assert(s == sizeof(inflate_huft) && n <= *(intf *)q, + "inflate_trees falloc overflow"); + *(intf *)q -= n+s-s; /* s-s to avoid warning */ + return (voidpf)(fixed_mem + *(intf *)q); +} + + +int inflate_trees_fixed(bl, bd, tl, td) +uIntf *bl; /* literal desired/actual bit depth */ +uIntf *bd; /* distance desired/actual bit depth */ +inflate_huft * FAR *tl; /* literal/length tree result */ +inflate_huft * FAR *td; /* distance tree result */ +{ + /* build fixed tables if not already (multiple overlapped executions ok) */ + if (!fixed_built) + { + int k; /* temporary variable */ + unsigned c[288]; /* length list for huft_build */ + z_stream z; /* for falloc function */ + int f = FIXEDH; /* number of hufts left in fixed_mem */ + + /* set up fake z_stream for memory routines */ + z.zalloc = falloc; + z.zfree = Z_NULL; + z.opaque = (voidpf)&f; + + /* literal table */ + for (k = 0; k < 144; k++) + c[k] = 8; + for (; k < 256; k++) + c[k] = 9; + for (; k < 280; k++) + c[k] = 7; + for (; k < 288; k++) + c[k] = 8; + fixed_bl = 7; + huft_build(c, 288, 257, cplens, cplext, &fixed_tl, &fixed_bl, &z); + + /* distance table */ + for (k = 0; k < 30; k++) + c[k] = 5; + fixed_bd = 5; + huft_build(c, 30, 0, cpdist, cpdext, &fixed_td, &fixed_bd, &z); + + /* done */ + Assert(f == 0, "invalid build of fixed tables"); + fixed_built = 1; + } + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} + + +int inflate_trees_free(t, z) +inflate_huft *t; /* table to free */ +z_streamp z; /* for zfree function */ +/* Free the malloc'ed tables built by huft_build(), which makes a linked + list of the tables it made, with the links in a dummy first entry of + each table. */ +{ + register inflate_huft *p, *q, *r; + + /* Reverse linked list */ + p = Z_NULL; + q = t; + while (q != Z_NULL) + { + r = (q - 1)->next; + (q - 1)->next = p; + p = q; + q = r; + } + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + while (p != Z_NULL) + { + q = (--p)->next; + ZFREE(z,p); + p = q; + } + return Z_OK; +} diff --git a/security/nss/cmd/zlib/inftrees.h b/security/nss/cmd/zlib/inftrees.h new file mode 100644 index 000000000..b06613ddd --- /dev/null +++ b/security/nss/cmd/zlib/inftrees.h @@ -0,0 +1,59 @@ +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s FAR inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + Bytef *pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit machines) */ + union { + uInt Base; /* literal, length base, or distance base */ + inflate_huft *Next; /* pointer to next level of table */ + } more; +}; + +#ifdef DEBUG + extern uInt inflate_hufts; +#endif + +extern int inflate_trees_bits OF(( + uIntf *, /* 19 code lengths */ + uIntf *, /* bits tree desired/actual depth */ + inflate_huft * FAR *, /* bits tree result */ + z_streamp )); /* for zalloc, zfree functions */ + +extern int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uIntf *, /* that many (total) code lengths */ + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *, /* distance tree result */ + z_streamp )); /* for zalloc, zfree functions */ + +extern int inflate_trees_fixed OF(( + uIntf *, /* literal desired/actual bit depth */ + uIntf *, /* distance desired/actual bit depth */ + inflate_huft * FAR *, /* literal/length tree result */ + inflate_huft * FAR *)); /* distance tree result */ + +extern int inflate_trees_free OF(( + inflate_huft *, /* tables to free */ + z_streamp )); /* for zfree function */ + diff --git a/security/nss/cmd/zlib/infutil.c b/security/nss/cmd/zlib/infutil.c new file mode 100644 index 000000000..eb21199c3 --- /dev/null +++ b/security/nss/cmd/zlib/infutil.c @@ -0,0 +1,87 @@ +/* inflate_util.c -- data and routines common to blocks and codes + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#include "zutil.h" +#include "infblock.h" +#include "inftrees.h" +#include "infcodes.h" +#include "infutil.h" + +struct inflate_codes_state {int dummy;}; /* for buggy compilers */ + +/* And'ing with mask[n] masks the lower n bits */ +uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + + +/* copy as much as possible from the sliding window to the output area */ +int inflate_flush(s, z, r) +inflate_blocks_statef *s; +z_streamp z; +int r; +{ + uInt n; + Bytef *p; + Bytef *q; + + /* local copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as far as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy as far as end of window */ + zmemcpy(p, q, n); + p += n; + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + zmemcpy(p, q, n); + p += n; + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} diff --git a/security/nss/cmd/zlib/infutil.h b/security/nss/cmd/zlib/infutil.h new file mode 100644 index 000000000..702cd290c --- /dev/null +++ b/security/nss/cmd/zlib/infutil.h @@ -0,0 +1,99 @@ +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995-1996 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFUTIL_H +#define _INFUTIL_H + +typedef enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONE, /* finished last block, done */ + BAD} /* got a data error--stuck here */ +inflate_block_mode; + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + inflate_block_mode mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uIntf *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_huft *tl; + inflate_huft *td; /* trees to free */ + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + Bytef *window; /* sliding window */ + Bytef *end; /* one byte after sliding window */ + Bytef *read; /* window read pointer */ + Bytef *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<<k;k+=8;}} +#define DUMPBITS(j) {b>>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(q<s->read?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load local pointers */ +#define LOAD {LOADIN LOADOUT} + +/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ +extern uInt inflate_mask[17]; + +/* copy as much as possible from the sliding window to the output area */ +extern int inflate_flush OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +struct internal_state {int dummy;}; /* for buggy compilers */ + +#endif diff --git a/security/nss/cmd/zlib/makefile.win b/security/nss/cmd/zlib/makefile.win new file mode 100644 index 000000000..0f87b40b8 --- /dev/null +++ b/security/nss/cmd/zlib/makefile.win @@ -0,0 +1,91 @@ +NODEPEND=1 +IGNORE_MANIFEST = 1 + +#//------------------------------------------------------------------------ +#// +# New build system where zip dll is build indepenant of java stubs. +#// +#//------------------------------------------------------------------------ +MODULE = zlib +EXPORTS = \ + zlib.h \ + zconf.h \ + $(NULL) + + +#//------------------------------------------------------------------------ +#// +#// Specify the depth of the current directory relative to the +#// root of NS +#// +#//------------------------------------------------------------------------ +DEPTH= ..\..\..\ + +MAKE_OBJ_TYPE=DLL +#//------------------------------------------------------------------------ +#// +#// Define any Public Make Variables here: (ie. PDFFILE, MAPFILE, ...) +#// +#//------------------------------------------------------------------------ +DLLNAME=$(ZIPDLL) +PDBFILE=$(MOD_ZIP).pdb +MAPFILE=$(MOD_ZIP).map +!if "$(MOZ_BITS)" == "16" +DEFFILE=zip16.def +!endif +#RESFILE=zip.res + +#//------------------------------------------------------------------------ +#// +#// Define the files necessary to build the target (ie. OBJS) +#// +#//------------------------------------------------------------------------ +OBJS= \ + .\$(OBJDIR)\adler32.obj \ + .\$(OBJDIR)\compress.obj \ + .\$(OBJDIR)\crc32.obj \ + .\$(OBJDIR)\deflate.obj \ + .\$(OBJDIR)\gzio.obj \ + .\$(OBJDIR)\infblock.obj \ + .\$(OBJDIR)\infcodes.obj \ + .\$(OBJDIR)\inffast.obj \ + .\$(OBJDIR)\inflate.obj \ + .\$(OBJDIR)\inftrees.obj \ + .\$(OBJDIR)\infutil.obj \ + .\$(OBJDIR)\trees.obj \ + .\$(OBJDIR)\uncompr.obj \ + .\$(OBJDIR)\zutil.obj \ + $(NULL) + +#//------------------------------------------------------------------------ +#// +#// Define any Public Targets here (ie. PROGRAM, LIBRARY, DLL, ...) +#// (these must be defined before the common makefiles are included) +#// +#//------------------------------------------------------------------------ + +DLL=.\$(OBJDIR)\$(DLLNAME) +MAPFILE= $(MOD_ZIP).map + + +#//------------------------------------------------------------------------ +#// +#// Define any local options for the make tools +#// (ie. LCFLAGS, LLFLAGS, LLIBS, LINCS) +#// +#//------------------------------------------------------------------------ +LLIBS=$(LLIBS) $(LIBNSPR) +LINCS=$(LINCS) -I. -I_gen +# clobber and clobber_all will remove the following garbage: +GARBAGE = $(GARBAGE) _gen + +#//------------------------------------------------------------------------ +#// +#// Include the common makefile rules +#// +#//------------------------------------------------------------------------ +include <$(DEPTH)/sun-java/config/rules.mak> + +export:: $(DLL) + $(MAKE_INSTALL) .\$(OBJDIR)\$(DLLNAME) $(DIST)\bin + $(MAKE_INSTALL) .\$(OBJDIR)\$(MOD_ZIP).lib $(DIST)\lib diff --git a/security/nss/cmd/zlib/maketree.c b/security/nss/cmd/zlib/maketree.c new file mode 100644 index 000000000..a16d4b146 --- /dev/null +++ b/security/nss/cmd/zlib/maketree.c @@ -0,0 +1,85 @@ +/* maketree.c -- make inffixed.h table for decoding fixed codes + * Copyright (C) 1995-2002 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* This program is included in the distribution for completeness. + You do not need to compile or run this program since inffixed.h + is already included in the distribution. To use this program + you need to compile zlib with BUILDFIXED defined and then compile + and link this program with the zlib library. Then the output of + this program can be piped to inffixed.h. */ + +#include <stdio.h> +#include <stdlib.h> +#include "zutil.h" +#include "inftrees.h" + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* generate initialization table for an inflate_huft structure array */ +void maketree(uInt b, inflate_huft *t) +{ + int i, e; + + i = 0; + while (1) + { + e = t[i].exop; + if (e && (e & (16+64)) == 0) /* table pointer */ + { + fprintf(stderr, "maketree: cannot initialize sub-tables!\n"); + exit(1); + } + if (i % 4 == 0) + printf("\n "); + printf(" {{{%u,%u}},%u}", t[i].exop, t[i].bits, t[i].base); + if (++i == (1<<b)) + break; + putchar(','); + } + puts(""); +} + +/* create the fixed tables in C initialization syntax */ +void main(void) +{ + int r; + uInt bl, bd; + inflate_huft *tl, *td; + z_stream z; + + z.zalloc = zcalloc; + z.opaque = (voidpf)0; + z.zfree = zcfree; + r = inflate_trees_fixed(&bl, &bd, &tl, &td, &z); + if (r) + { + fprintf(stderr, "inflate_trees_fixed error %d\n", r); + return; + } + puts("/* inffixed.h -- table for decoding fixed codes"); + puts(" * Generated automatically by the maketree.c program"); + puts(" */"); + puts(""); + puts("/* WARNING: this file should *not* be used by applications. It is"); + puts(" part of the implementation of the compression library and is"); + puts(" subject to change. Applications should only use zlib.h."); + puts(" */"); + puts(""); + printf("local uInt fixed_bl = %d;\n", bl); + printf("local uInt fixed_bd = %d;\n", bd); + printf("local inflate_huft fixed_tl[] = {"); + maketree(bl, tl); + puts(" };"); + printf("local inflate_huft fixed_td[] = {"); + maketree(bd, td); + puts(" };"); +} diff --git a/security/nss/cmd/zlib/manifest.mn b/security/nss/cmd/zlib/manifest.mn new file mode 100644 index 000000000..13460377c --- /dev/null +++ b/security/nss/cmd/zlib/manifest.mn @@ -0,0 +1,60 @@ +# +# The contents of this file are subject to the Mozilla Public +# License Version 1.1 (the "License"); you may not use this file +# except in compliance with the License. You may obtain a copy of +# the License at http://www.mozilla.org/MPL/ +# +# Software distributed under the License is distributed on an "AS +# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or +# implied. See the License for the specific language governing +# rights and limitations under 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 = ../../.. + +MODULE = seccmd + +EXPORTS = zlib.h zconf.h + +CSRCS = adler32.c \ + crc32.c \ + compress.c \ + uncompr.c \ + deflate.c \ + trees.c \ + zutil.c \ + inflate.c \ + infblock.c \ + inftrees.c \ + infcodes.c \ + infutil.c \ + inffast.c \ + $(NULL) + +LIBRARY_NAME = zlib + +# REQUIRES = nss + +DEFINES = -DNSPR20=1 -DMOZILLA_CLIENT=1 + diff --git a/security/nss/cmd/zlib/minigzip.c b/security/nss/cmd/zlib/minigzip.c new file mode 100644 index 000000000..60a48a12d --- /dev/null +++ b/security/nss/cmd/zlib/minigzip.c @@ -0,0 +1,246 @@ +/* minigzip.c -- simulate gzip using the zlib compression library + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* + * minigzip is a minimal implementation of the gzip utility. This is + * only an example of using zlib and isn't meant to replace the + * full-featured gzip. No attempt is made to deal with file systems + * limiting names to 14 or 8+3 characters, etc... Error checking is + * very limited. So use minigzip only for testing; use gzip for the + * real thing. On MSDOS, use only on file names without extension + * or in pipe mode. + */ + +/* $Id$ */ + +#include <stdio.h> +#include "zlib.h" + +#ifdef STDC +# include <string.h> +# include <stdlib.h> +#else + extern void exit OF((int)); +#endif + + +#if defined(MSDOS) || defined(OS2) || defined(WIN32) +# include <fcntl.h> +# include <io.h> +# define SET_BINARY_MODE(file) setmode(fileno(file), O_BINARY) +#else +# define SET_BINARY_MODE(file) +#endif + +#ifdef VMS +# define unlink delete +# define GZ_SUFFIX "-gz" +#endif +#ifdef RISCOS +# define unlink remove +# define GZ_SUFFIX "-gz" +# define fileno(file) file->__file +#endif + +#ifndef GZ_SUFFIX +# define GZ_SUFFIX ".gz" +#endif +#define SUFFIX_LEN sizeof(GZ_SUFFIX) + +extern int unlink OF((const char *)); + +#define BUFLEN 4096 +#define MAX_NAME_LEN 1024 + +#define local static +/* For MSDOS and other systems with limitation on stack size. For Unix, + #define local + works also. + */ + +char *prog; + +void error OF((const char *msg)); +void gz_compress OF((FILE *in, gzFile out)); +void gz_uncompress OF((gzFile in, FILE *out)); +void file_compress OF((char *file)); +void file_uncompress OF((char *file)); +int main OF((int argc, char *argv[])); + +/* =========================================================================== + * Display error message and exit + */ +void error(msg) + const char *msg; +{ + fprintf(stderr, "%s: %s\n", prog, msg); + exit(1); +} + +/* =========================================================================== + * Compress input to output then close both files. + */ +void gz_compress(in, out) + FILE *in; + gzFile out; +{ + local char buf[BUFLEN]; + int len; + int err; + + for (;;) { + len = fread(buf, 1, sizeof(buf), in); + if (ferror(in)) { + perror("fread"); + exit(1); + } + if (len == 0) break; + + if (gzwrite(out, buf, (unsigned)len) != len) error(gzerror(out, &err)); + } + fclose(in); + if (gzclose(out) != Z_OK) error("failed gzclose"); +} + +/* =========================================================================== + * Uncompress input to output then close both files. + */ +void gz_uncompress(in, out) + gzFile in; + FILE *out; +{ + local char buf[BUFLEN]; + int len; + int err; + + for (;;) { + len = gzread(in, buf, sizeof(buf)); + if (len < 0) error (gzerror(in, &err)); + if (len == 0) break; + + if ((int)fwrite(buf, 1, (unsigned)len, out) != len) { + error("failed fwrite"); + } + } + if (fclose(out)) error("failed fclose"); + + if (gzclose(in) != Z_OK) error("failed gzclose"); +} + + +/* =========================================================================== + * Compress the given file: create a corresponding .gz file and remove the + * original. + */ +void file_compress(file) + char *file; +{ + local char outfile[MAX_NAME_LEN]; + FILE *in; + gzFile out; + + strcpy(outfile, file); + strcat(outfile, GZ_SUFFIX); + + in = fopen(file, "rb"); + if (in == NULL) { + perror(file); + exit(1); + } + out = gzopen(outfile, "wb"); /* use "wb9" for maximal compression */ + if (out == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, outfile); + exit(1); + } + gz_compress(in, out); + + unlink(file); +} + + +/* =========================================================================== + * Uncompress the given file and remove the original. + */ +void file_uncompress(file) + char *file; +{ + local char buf[MAX_NAME_LEN]; + char *infile, *outfile; + FILE *out; + gzFile in; + int len = strlen(file); + + strcpy(buf, file); + + if (len > SUFFIX_LEN && strcmp(file+len-SUFFIX_LEN, GZ_SUFFIX) == 0) { + infile = file; + outfile = buf; + outfile[len-3] = '\0'; + } else { + outfile = file; + infile = buf; + strcat(infile, GZ_SUFFIX); + } + in = gzopen(infile, "rb"); + if (in == NULL) { + fprintf(stderr, "%s: can't gzopen %s\n", prog, infile); + exit(1); + } + out = fopen(outfile, "wb"); + if (out == NULL) { + perror(file); + exit(1); + } + + gz_uncompress(in, out); + + unlink(infile); +} + + +/* =========================================================================== + * Usage: minigzip [-d] [files...] + */ + +int main(argc, argv) + int argc; + char *argv[]; +{ + int uncompr = 0; + gzFile file; + + prog = argv[0]; + argc--, argv++; + + if (argc > 0) { + uncompr = (strcmp(*argv, "-d") == 0); + if (uncompr) { + argc--, argv++; + } + } + if (argc == 0) { + SET_BINARY_MODE(stdin); + SET_BINARY_MODE(stdout); + if (uncompr) { + file = gzdopen(fileno(stdin), "rb"); + if (file == NULL) error("can't gzdopen stdin"); + gz_uncompress(file, stdout); + } else { + file = gzdopen(fileno(stdout), "wb"); /* "wb9" for max compr. */ + if (file == NULL) error("can't gzdopen stdout"); + gz_compress(stdin, file); + } + } else { + do { + if (uncompr) { + file_uncompress(*argv); + } else { + file_compress(*argv); + } + } while (argv++, --argc); + } + exit(0); + return 0; /* to avoid warning */ +} diff --git a/security/nss/cmd/zlib/netscape_mods.doc b/security/nss/cmd/zlib/netscape_mods.doc new file mode 100644 index 000000000..c8a72d159 --- /dev/null +++ b/security/nss/cmd/zlib/netscape_mods.doc @@ -0,0 +1,43 @@ + +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * + * The contents of this file are subject to the Netscape Public + * License Version 1.1 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.mozilla.org/NPL/ + * + * Software distributed under the License is distributed on an "AS + * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or + * implied. See the License for the specific language governing + * rights and limitations under the License. + * + * The Original Code is mozilla.org code. + * + * The Initial Developer of the Original Code is Netscape + * Communications Corporation. Portions created by Netscape are + * Copyright (C) 1998 Netscape Communications Corporation. All + * Rights Reserved. + * + * Contributor(s): + */ + +Netscape Modifications to Zlib source - + + +Changes were made to the following files to +create a zlib dll: + + adler32.c + compress.c + crc32.c + deflate.c + gzio.c + inflate.c + uncompr.c + zutil.c + + +Various changes for cross platform builds +are clearly marked through out the source. + + diff --git a/security/nss/cmd/zlib/trees.c b/security/nss/cmd/zlib/trees.c new file mode 100644 index 000000000..84623d992 --- /dev/null +++ b/security/nss/cmd/zlib/trees.c @@ -0,0 +1,1143 @@ +/* trees.c -- output deflated data using Huffman coding + * Copyright (C) 1995-1996 Jean-loup Gailly + * For conditions of distribution and use, see copyright notice in zlib.h + */ +/* This file was modified since it was taken from the zlib distribution */ +/* + * ALGORITHM + * + * The "deflation" process uses several Huffman trees. The more + * common source values are represented by shorter bit sequences. + * + * Each code tree is stored in a compressed form which is itself + * a Huffman encoding of the lengths of all the code strings (in + * ascending order by source values). The actual code strings are + * reconstructed from the lengths in the inflate process, as described + * in the deflate specification. + * + * REFERENCES + * + * Deutsch, L.P.,"'Deflate' Compressed Data Format Specification". + * Available in ftp.uu.net:/pub/archiving/zip/doc/deflate-1.1.doc + * + * Storer, James A. + * Data Compression: Methods and Theory, pp. 49-50. + * Computer Science Press, 1988. ISBN 0-7167-8156-5. + * + * Sedgewick, R. + * Algorithms, p290. + * Addison-Wesley, 1983. ISBN 0-201-06672-6. + */ + +/* $Id$ */ + +#include "deflate.h" + +#ifdef DEBUG +# include <ctype.h> +#endif + +/* =========================================================================== + * Constants + */ + +#define MAX_BL_BITS 7 +/* Bit length codes must not exceed MAX_BL_BITS bits */ + +#define END_BLOCK 256 +/* end of block literal code */ + +#define REP_3_6 16 +/* repeat previous bit length 3-6 times (2 bits of repeat count) */ + +#define REPZ_3_10 17 +/* repeat a zero length 3-10 times (3 bits of repeat count) */ + +#define REPZ_11_138 18 +/* repeat a zero length 11-138 times (7 bits of repeat count) */ + +local int extra_lbits[LENGTH_CODES] /* extra bits for each length code */ + = {0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0}; + +local int extra_dbits[D_CODES] /* extra bits for each distance code */ + = {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; + +local int extra_blbits[BL_CODES]/* extra bits for each bit length code */ + = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7}; + +local uch bl_order[BL_CODES] + = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15}; +/* The lengths of the bit length codes are sent in order of decreasing + * probability, to avoid transmitting the lengths for unused bit length codes. + */ + +#define Buf_size (8 * 2*sizeof(char)) +/* Number of bits used within bi_buf. (bi_buf might be implemented on + * more than 16 bits on some systems.) + */ + +/* =========================================================================== + * Local data. These are initialized only once. + */ + +local ct_data static_ltree[L_CODES+2]; +/* The static literal tree. Since the bit lengths are imposed, there is no + * need for the L_CODES extra codes used during heap construction. However + * The codes 286 and 287 are needed to build a canonical tree (see _tr_init + * below). + */ + +local ct_data static_dtree[D_CODES]; +/* The static distance tree. (Actually a trivial tree since all codes use + * 5 bits.) + */ + +local uch dist_code[512]; +/* distance codes. The first 256 values correspond to the distances + * 3 .. 258, the last 256 values correspond to the top 8 bits of + * the 15 bit distances. + */ + +local uch length_code[MAX_MATCH-MIN_MATCH+1]; +/* length code for each normalized match length (0 == MIN_MATCH) */ + +local int base_length[LENGTH_CODES]; +/* First normalized length for each code (0 = MIN_MATCH) */ + +local int base_dist[D_CODES]; +/* First normalized distance for each code (0 = distance of 1) */ + +struct static_tree_desc_s { + ct_data *static_tree; /* static tree or NULL */ + intf *extra_bits; /* extra bits for each code or NULL */ + int extra_base; /* base index for extra_bits */ + int elems; /* max number of elements in the tree */ + int max_length; /* max bit length for the codes */ +}; + +local static_tree_desc static_l_desc = +{static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS}; + +local static_tree_desc static_d_desc = +{static_dtree, extra_dbits, 0, D_CODES, MAX_BITS}; + +local static_tree_desc static_bl_desc = +{(ct_data *)0, extra_blbits, 0, BL_CODES, MAX_BL_BITS}; + +/* =========================================================================== + * Local (static) routines in this file. + */ + +local void tr_static_init OF((void)); +local void init_block OF((deflate_state *s)); +local void pqdownheap OF((deflate_state *s, ct_data *tree, int k)); +local void gen_bitlen OF((deflate_state *s, tree_desc *desc)); +local void gen_codes OF((ct_data *tree, int max_code, ushf *bl_count)); +local void build_tree OF((deflate_state *s, tree_desc *desc)); +local void scan_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local void send_tree OF((deflate_state *s, ct_data *tree, int max_code)); +local int build_bl_tree OF((deflate_state *s)); +local void send_all_trees OF((deflate_state *s, int lcodes, int dcodes, + int blcodes)); +local void compress_block OF((deflate_state *s, ct_data *ltree, + ct_data *dtree)); +local void set_data_type OF((deflate_state *s)); +local unsigned bi_reverse OF((unsigned value, int length)); +local void bi_windup OF((deflate_state *s)); +local void bi_flush OF((deflate_state *s)); +local void copy_block OF((deflate_state *s, charf *buf, unsigned len, + int header)); + +#ifndef DEBUG_NEVER +# define send_code(s, c, tree) send_bits(s, tree[c].Code, tree[c].Len) + /* Send a code of the given tree. c and tree must not have side effects */ + +#else /* DEBUG */ +# define send_code(s, c, tree) \ + { if (verbose>2) fprintf(stderr,"\ncd %3d ",(c)); \ + send_bits(s, tree[c].Code, tree[c].Len); } +#endif + +#define d_code(dist) \ + ((dist) < 256 ? dist_code[dist] : dist_code[256+((dist)>>7)]) +/* Mapping from a distance to a distance code. dist is the distance - 1 and + * must not have side effects. dist_code[256] and dist_code[257] are never + * used. + */ + +/* =========================================================================== + * Output a short LSB first on the stream. + * IN assertion: there is enough room in pendingBuf. + */ +#define put_short(s, w) { \ + put_byte(s, (uch)((w) & 0xff)); \ + put_byte(s, (uch)((ush)(w) >> 8)); \ +} + +/* =========================================================================== + * Send a value on a given number of bits. + * IN assertion: length <= 16 and value fits in length bits. + */ +#ifdef DEBUG +local void send_bits OF((deflate_state *s, int value, int length)); + +local void send_bits(s, value, length) + deflate_state *s; + int value; /* value to send */ + int length; /* number of bits */ +{ + Tracevv((stderr," l %2d v %4x ", length, value)); + Assert(length > 0 && length <= 15, "invalid length"); + s->bits_sent += (ulg)length; + + /* If not enough room in bi_buf, use (valid) bits from bi_buf and + * (16 - bi_valid) bits from value, leaving (width - (16-bi_valid)) + * unused bits in value. + */ + if (s->bi_valid > (int)Buf_size - length) { + s->bi_buf |= (value << s->bi_valid); + put_short(s, s->bi_buf); + s->bi_buf = (ush)value >> (Buf_size - s->bi_valid); + s->bi_valid += length - Buf_size; + } else { + s->bi_buf |= value << s->bi_valid; + s->bi_valid += length; + } +} +#else /* !DEBUG */ + +#define send_bits(s, value, length) \ +{ int len = length;\ + if (s->bi_valid > (int)Buf_size - len) {\ + int val = value;\ + s->bi_buf |= (val << s->bi_valid);\ + put_short(s, s->bi_buf);\ + s->bi_buf = (ush)val >> (Buf_size - s->bi_valid);\ + s->bi_valid += len - Buf_size;\ + } else {\ + s->bi_buf |= (value) << s->bi_valid;\ + s->bi_valid += len;\ + }\ +} +#endif /* DEBUG */ + + +#ifndef MAX +#define MAX(a,b) (a >= b ? a : b) +#endif +/* the arguments must not have side effects */ + +/* =========================================================================== + * Initialize the various 'constant' tables. In a multi-threaded environment, + * this function may be called by two threads concurrently, but this is + * harmless since both invocations do exactly the same thing. + */ +local void tr_static_init() +{ + static int static_init_done = 0; + int n; /* iterates over tree elements */ + int bits; /* bit counter */ + int length; /* length value */ + int code; /* code value */ + int dist; /* distance index */ + ush bl_count[MAX_BITS+1]; + /* number of codes at each bit length for an optimal tree */ + + if (static_init_done) return; + + /* Initialize the mapping length (0..255) -> length code (0..28) */ + length = 0; + for (code = 0; code < LENGTH_CODES-1; code++) { + base_length[code] = length; + for (n = 0; n < (1<<extra_lbits[code]); n++) { + length_code[length++] = (uch)code; + } + } + Assert (length == 256, "tr_static_init: length != 256"); + /* Note that the length 255 (match length 258) can be represented + * in two different ways: code 284 + 5 bits or code 285, so we + * overwrite length_code[255] to use the best encoding: + */ + length_code[length-1] = (uch)code; + + /* Initialize the mapping dist (0..32K) -> dist code (0..29) */ + dist = 0; + for (code = 0 ; code < 16; code++) { + base_dist[code] = dist; + for (n = 0; n < (1<<extra_dbits[code]); n++) { + dist_code[dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: dist != 256"); + dist >>= 7; /* from now on, all distances are divided by 128 */ + for ( ; code < D_CODES; code++) { + base_dist[code] = dist << 7; + for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) { + dist_code[256 + dist++] = (uch)code; + } + } + Assert (dist == 256, "tr_static_init: 256+dist != 512"); + + /* Construct the codes of the static literal tree */ + for (bits = 0; bits <= MAX_BITS; bits++) bl_count[bits] = 0; + n = 0; + while (n <= 143) static_ltree[n++].Len = 8, bl_count[8]++; + while (n <= 255) static_ltree[n++].Len = 9, bl_count[9]++; + while (n <= 279) static_ltree[n++].Len = 7, bl_count[7]++; + while (n <= 287) static_ltree[n++].Len = 8, bl_count[8]++; + /* Codes 286 and 287 do not exist, but we must include them in the + * tree construction to get a canonical Huffman tree (longest code + * all ones) + */ + gen_codes((ct_data *)static_ltree, L_CODES+1, bl_count); + + /* The static distance tree is trivial: */ + for (n = 0; n < D_CODES; n++) { + static_dtree[n].Len = 5; + static_dtree[n].Code = bi_reverse((unsigned)n, 5); + } + static_init_done = 1; +} + +/* =========================================================================== + * Initialize the tree data structures for a new zlib stream. + */ +void _tr_init(s) + deflate_state *s; +{ + tr_static_init(); + + s->compressed_len = 0L; + + s->l_desc.dyn_tree = s->dyn_ltree; + s->l_desc.stat_desc = &static_l_desc; + + s->d_desc.dyn_tree = s->dyn_dtree; + s->d_desc.stat_desc = &static_d_desc; + + s->bl_desc.dyn_tree = s->bl_tree; + s->bl_desc.stat_desc = &static_bl_desc; + + s->bi_buf = 0; + s->bi_valid = 0; + s->last_eob_len = 8; /* enough lookahead for inflate */ +#ifdef DEBUG + s->bits_sent = 0L; +#endif + + /* Initialize the first block of the first file: */ + init_block(s); +} + +/* =========================================================================== + * Initialize a new block. + */ +local void init_block(s) + deflate_state *s; +{ + int n; /* iterates over tree elements */ + + /* Initialize the trees. */ + for (n = 0; n < L_CODES; n++) s->dyn_ltree[n].Freq = 0; + for (n = 0; n < D_CODES; n++) s->dyn_dtree[n].Freq = 0; + for (n = 0; n < BL_CODES; n++) s->bl_tree[n].Freq = 0; + + s->dyn_ltree[END_BLOCK].Freq = 1; + s->opt_len = s->static_len = 0L; + s->last_lit = s->matches = 0; +} + +#define SMALLEST 1 +/* Index within the heap array of least frequent node in the Huffman tree */ + + +/* =========================================================================== + * Remove the smallest element from the heap and recreate the heap with + * one less element. Updates heap and heap_len. + */ +#define pqremove(s, tree, top) \ +{\ + top = s->heap[SMALLEST]; \ + s->heap[SMALLEST] = s->heap[s->heap_len--]; \ + pqdownheap(s, tree, SMALLEST); \ +} + +/* =========================================================================== + * Compares to subtrees, using the tree depth as tie breaker when + * the subtrees have equal frequency. This minimizes the worst case length. + */ +#define smaller(tree, n, m, depth) \ + (tree[n].Freq < tree[m].Freq || \ + (tree[n].Freq == tree[m].Freq && depth[n] <= depth[m])) + +/* =========================================================================== + * Restore the heap property by moving down the tree starting at node k, + * exchanging a node with the smallest of its two sons if necessary, stopping + * when the heap property is re-established (each father smaller than its + * two sons). + */ +local void pqdownheap(s, tree, k) + deflate_state *s; + ct_data *tree; /* the tree to restore */ + int k; /* node to move down */ +{ + int v = s->heap[k]; + int j = k << 1; /* left son of k */ + while (j <= s->heap_len) { + /* Set j to the smallest of the two sons: */ + if (j < s->heap_len && + smaller(tree, s->heap[j+1], s->heap[j], s->depth)) { + j++; + } + /* Exit if v is smaller than both sons */ + if (smaller(tree, v, s->heap[j], s->depth)) break; + + /* Exchange v with the smallest son */ + s->heap[k] = s->heap[j]; k = j; + + /* And continue down the tree, setting j to the left son of k */ + j <<= 1; + } + s->heap[k] = v; +} + +/* =========================================================================== + * Compute the optimal bit lengths for a tree and update the total bit length + * for the current block. + * IN assertion: the fields freq and dad are set, heap[heap_max] and + * above are the tree nodes sorted by increasing frequency. + * OUT assertions: the field len is set to the optimal bit length, the + * array bl_count contains the frequencies for each bit length. + * The length opt_len is updated; static_len is also updated if stree is + * not null. + */ +local void gen_bitlen(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + int max_code = desc->max_code; + ct_data *stree = desc->stat_desc->static_tree; + intf *extra = desc->stat_desc->extra_bits; + int base = desc->stat_desc->extra_base; + int max_length = desc->stat_desc->max_length; + int h; /* heap index */ + int n, m; /* iterate over the tree elements */ + int bits; /* bit length */ + int xbits; /* extra bits */ + ush f; /* frequency */ + int overflow = 0; /* number of elements with bit length too large */ + + for (bits = 0; bits <= MAX_BITS; bits++) s->bl_count[bits] = 0; + + /* In a first pass, compute the optimal bit lengths (which may + * overflow in the case of the bit length tree). + */ + tree[s->heap[s->heap_max]].Len = 0; /* root of the heap */ + + for (h = s->heap_max+1; h < HEAP_SIZE; h++) { + n = s->heap[h]; + bits = tree[tree[n].Dad].Len + 1; + if (bits > max_length) bits = max_length, overflow++; + tree[n].Len = (ush)bits; + /* We overwrite tree[n].Dad which is no longer needed */ + + if (n > max_code) continue; /* not a leaf node */ + + s->bl_count[bits]++; + xbits = 0; + if (n >= base) xbits = extra[n-base]; + f = tree[n].Freq; + s->opt_len += (ulg)f * (bits + xbits); + if (stree) s->static_len += (ulg)f * (stree[n].Len + xbits); + } + if (overflow == 0) return; + + Trace((stderr,"\nbit length overflow\n")); + /* This happens for example on obj2 and pic of the Calgary corpus */ + + /* Find the first bit length which could increase: */ + do { + bits = max_length-1; + while (s->bl_count[bits] == 0) bits--; + s->bl_count[bits]--; /* move one leaf down the tree */ + s->bl_count[bits+1] += 2; /* move one overflow item as its brother */ + s->bl_count[max_length]--; + /* The brother of the overflow item also moves one step up, + * but this does not affect bl_count[max_length] + */ + overflow -= 2; + } while (overflow > 0); + + /* Now recompute all bit lengths, scanning in increasing frequency. + * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all + * lengths instead of fixing only the wrong ones. This idea is taken + * from 'ar' written by Haruhiko Okumura.) + */ + for (bits = max_length; bits != 0; bits--) { + n = s->bl_count[bits]; + while (n != 0) { + m = s->heap[--h]; + if (m > max_code) continue; + if (tree[m].Len != (unsigned) bits) { + Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits)); + s->opt_len += ((long)bits - (long)tree[m].Len) + *(long)tree[m].Freq; + tree[m].Len = (ush)bits; + } + n--; + } + } +} + +/* =========================================================================== + * Generate the codes for a given tree and bit counts (which need not be + * optimal). + * IN assertion: the array bl_count contains the bit length statistics for + * the given tree and the field len is set for all tree elements. + * OUT assertion: the field code is set for all tree elements of non + * zero code length. + */ +local void gen_codes (tree, max_code, bl_count) + ct_data *tree; /* the tree to decorate */ + int max_code; /* largest code with non zero frequency */ + ushf *bl_count; /* number of codes at each bit length */ +{ + ush next_code[MAX_BITS+1]; /* next code value for each bit length */ + ush code = 0; /* running code value */ + int bits; /* bit index */ + int n; /* code index */ + + /* The distribution counts are first used to generate the code values + * without bit reversal. + */ + for (bits = 1; bits <= MAX_BITS; bits++) { + next_code[bits] = code = (code + bl_count[bits-1]) << 1; + } + /* Check that the bit counts in bl_count are consistent. The last code + * must be all ones. + */ + Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1, + "inconsistent bit counts"); + Tracev((stderr,"\ngen_codes: max_code %d ", max_code)); + + for (n = 0; n <= max_code; n++) { + int len = tree[n].Len; + if (len == 0) continue; + /* Now reverse the bits */ + tree[n].Code = bi_reverse(next_code[len]++, len); + + Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ", + n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1)); + } +} + +/* =========================================================================== + * Construct one Huffman tree and assigns the code bit strings and lengths. + * Update the total bit length for the current block. + * IN assertion: the field freq is set for all tree elements. + * OUT assertions: the fields len and code are set to the optimal bit length + * and corresponding code. The length opt_len is updated; static_len is + * also updated if stree is not null. The field max_code is set. + */ +local void build_tree(s, desc) + deflate_state *s; + tree_desc *desc; /* the tree descriptor */ +{ + ct_data *tree = desc->dyn_tree; + ct_data *stree = desc->stat_desc->static_tree; + int elems = desc->stat_desc->elems; + int n, m; /* iterate over heap elements */ + int max_code = -1; /* largest code with non zero frequency */ + int node; /* new node being created */ + + /* Construct the initial heap, with least frequent element in + * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1]. + * heap[0] is not used. + */ + s->heap_len = 0, s->heap_max = HEAP_SIZE; + + for (n = 0; n < elems; n++) { + if (tree[n].Freq != 0) { + s->heap[++(s->heap_len)] = max_code = n; + s->depth[n] = 0; + } else { + tree[n].Len = 0; + } + } + + /* The pkzip format requires that at least one distance code exists, + * and that at least one bit should be sent even if there is only one + * possible code. So to avoid special checks later on we force at least + * two codes of non zero frequency. + */ + while (s->heap_len < 2) { + node = s->heap[++(s->heap_len)] = (max_code < 2 ? ++max_code : 0); + tree[node].Freq = 1; + s->depth[node] = 0; + s->opt_len--; if (stree) s->static_len -= stree[node].Len; + /* node is 0 or 1 so it does not have extra bits */ + } + desc->max_code = max_code; + + /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree, + * establish sub-heaps of increasing lengths: + */ + for (n = s->heap_len/2; n >= 1; n--) pqdownheap(s, tree, n); + + /* Construct the Huffman tree by repeatedly combining the least two + * frequent nodes. + */ + node = elems; /* next internal node of the tree */ + do { + pqremove(s, tree, n); /* n = node of least frequency */ + m = s->heap[SMALLEST]; /* m = node of next least frequency */ + + s->heap[--(s->heap_max)] = n; /* keep the nodes sorted by frequency */ + s->heap[--(s->heap_max)] = m; + + /* Create a new node father of n and m */ + tree[node].Freq = tree[n].Freq + tree[m].Freq; + s->depth[node] = (uch) (MAX(s->depth[n], s->depth[m]) + 1); + tree[n].Dad = tree[m].Dad = (ush)node; +#ifdef DUMP_BL_TREE + if (tree == s->bl_tree) { + fprintf(stderr,"\nnode %d(%d), sons %d(%d) %d(%d)", + node, tree[node].Freq, n, tree[n].Freq, m, tree[m].Freq); + } +#endif + /* and insert the new node in the heap */ + s->heap[SMALLEST] = node++; + pqdownheap(s, tree, SMALLEST); + + } while (s->heap_len >= 2); + + s->heap[--(s->heap_max)] = s->heap[SMALLEST]; + + /* At this point, the fields freq and dad are set. We can now + * generate the bit lengths. + */ + gen_bitlen(s, (tree_desc *)desc); + + /* The field len is now set, we can generate the bit codes */ + gen_codes ((ct_data *)tree, max_code, s->bl_count); +} + +/* =========================================================================== + * Scan a literal or distance tree to determine the frequencies of the codes + * in the bit length tree. + */ +local void scan_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + if (nextlen == 0) max_count = 138, min_count = 3; + tree[max_code+1].Len = (ush)0xffff; /* guard */ + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + s->bl_tree[curlen].Freq += count; + } else if (curlen != 0) { + if (curlen != prevlen) s->bl_tree[curlen].Freq++; + s->bl_tree[REP_3_6].Freq++; + } else if (count <= 10) { + s->bl_tree[REPZ_3_10].Freq++; + } else { + s->bl_tree[REPZ_11_138].Freq++; + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Send a literal or distance tree in compressed form, using the codes in + * bl_tree. + */ +local void send_tree (s, tree, max_code) + deflate_state *s; + ct_data *tree; /* the tree to be scanned */ + int max_code; /* and its largest code of non zero frequency */ +{ + int n; /* iterates over all tree elements */ + int prevlen = -1; /* last emitted length */ + int curlen; /* length of current code */ + int nextlen = tree[0].Len; /* length of next code */ + int count = 0; /* repeat count of the current code */ + int max_count = 7; /* max repeat count */ + int min_count = 4; /* min repeat count */ + + /* tree[max_code+1].Len = -1; */ /* guard already set */ + if (nextlen == 0) max_count = 138, min_count = 3; + + for (n = 0; n <= max_code; n++) { + curlen = nextlen; nextlen = tree[n+1].Len; + if (++count < max_count && curlen == nextlen) { + continue; + } else if (count < min_count) { + do { send_code(s, curlen, s->bl_tree); } while (--count != 0); + + } else if (curlen != 0) { + if (curlen != prevlen) { + send_code(s, curlen, s->bl_tree); count--; + } + Assert(count >= 3 && count <= 6, " 3_6?"); + send_code(s, REP_3_6, s->bl_tree); send_bits(s, count-3, 2); + + } else if (count <= 10) { + send_code(s, REPZ_3_10, s->bl_tree); send_bits(s, count-3, 3); + + } else { + send_code(s, REPZ_11_138, s->bl_tree); send_bits(s, count-11, 7); + } + count = 0; prevlen = curlen; + if (nextlen == 0) { + max_count = 138, min_count = 3; + } else if (curlen == nextlen) { + max_count = 6, min_count = 3; + } else { + max_count = 7, min_count = 4; + } + } +} + +/* =========================================================================== + * Construct the Huffman tree for the bit lengths and return the index in + * bl_order of the last bit length code to send. + */ +local int build_bl_tree(s) + deflate_state *s; +{ + int max_blindex; /* index of last bit length code of non zero freq */ + + /* Determine the bit length frequencies for literal and distance trees */ + scan_tree(s, (ct_data *)s->dyn_ltree, s->l_desc.max_code); + scan_tree(s, (ct_data *)s->dyn_dtree, s->d_desc.max_code); + + /* Build the bit length tree: */ + build_tree(s, (tree_desc *)(&(s->bl_desc))); + /* opt_len now includes the length of the tree representations, except + * the lengths of the bit lengths codes and the 5+5+4 bits for the counts. + */ + + /* Determine the number of bit length codes to send. The pkzip format + * requires that at least 4 bit length codes be sent. (appnote.txt says + * 3 but the actual value used is 4.) + */ + for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) { + if (s->bl_tree[bl_order[max_blindex]].Len != 0) break; + } + /* Update opt_len to include the bit length tree and counts */ + s->opt_len += 3*(max_blindex+1) + 5+5+4; + Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld", + s->opt_len, s->static_len)); + + return max_blindex; +} + +/* =========================================================================== + * Send the header for a block using dynamic Huffman trees: the counts, the + * lengths of the bit length codes, the literal tree and the distance tree. + * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4. + */ +local void send_all_trees(s, lcodes, dcodes, blcodes) + deflate_state *s; + int lcodes, dcodes, blcodes; /* number of codes for each tree */ +{ + int rank; /* index in bl_order */ + + Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes"); + Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES, + "too many codes"); + Tracev((stderr, "\nbl counts: ")); + send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */ + send_bits(s, dcodes-1, 5); + send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */ + for (rank = 0; rank < blcodes; rank++) { + Tracev((stderr, "\nbl code %2d ", bl_order[rank])); + send_bits(s, s->bl_tree[bl_order[rank]].Len, 3); + } + Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_ltree, lcodes-1); /* literal tree */ + Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent)); + + send_tree(s, (ct_data *)s->dyn_dtree, dcodes-1); /* distance tree */ + Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent)); +} + +/* =========================================================================== + * Send a stored block + */ +void _tr_stored_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + send_bits(s, (STORED_BLOCK<<1)+eof, 3); /* send block type */ + s->compressed_len = (s->compressed_len + 3 + 7) & (ulg)~7L; + s->compressed_len += (stored_len + 4) << 3; + + copy_block(s, buf, (unsigned)stored_len, 1); /* with header */ +} + +/* =========================================================================== + * Send one empty static block to give enough lookahead for inflate. + * This takes 10 bits, of which 7 may remain in the bit buffer. + * The current inflate code requires 9 bits of lookahead. If the + * last two codes for the previous block (real code plus EOB) were coded + * on 5 bits or less, inflate may have only 5+3 bits of lookahead to decode + * the last real code. In this case we send two empty static blocks instead + * of one. (There are no problems if the previous block is stored or fixed.) + * To simplify the code, we assume the worst case of last real code encoded + * on one bit only. + */ +void _tr_align(s) + deflate_state *s; +{ + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); + s->compressed_len += 10L; /* 3 for block type, 7 for EOB */ + bi_flush(s); + /* Of the 10 bits for the empty block, we have already sent + * (10 - bi_valid) bits. The lookahead for the last real code (before + * the EOB of the previous block) was thus at least one plus the length + * of the EOB plus what we have just sent of the empty static block. + */ + if (1 + s->last_eob_len + 10 - s->bi_valid < 9) { + send_bits(s, STATIC_TREES<<1, 3); + send_code(s, END_BLOCK, static_ltree); + s->compressed_len += 10L; + bi_flush(s); + } + s->last_eob_len = 7; +} + +/* =========================================================================== + * Determine the best encoding for the current block: dynamic trees, static + * trees or store, and output the encoded block to the zip file. This function + * returns the total compressed length for the file so far. + */ +ulg _tr_flush_block(s, buf, stored_len, eof) + deflate_state *s; + charf *buf; /* input block, or NULL if too old */ + ulg stored_len; /* length of input block */ + int eof; /* true if this is the last block for a file */ +{ + ulg opt_lenb, static_lenb; /* opt_len and static_len in bytes */ + int max_blindex = 0; /* index of last bit length code of non zero freq */ + + /* Build the Huffman trees unless a stored block is forced */ + if (s->level > 0) { + + /* Check if the file is ascii or binary */ + if (s->data_type == Z_UNKNOWN) set_data_type(s); + + /* Construct the literal and distance trees */ + build_tree(s, (tree_desc *)(&(s->l_desc))); + Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + + build_tree(s, (tree_desc *)(&(s->d_desc))); + Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len, + s->static_len)); + /* At this point, opt_len and static_len are the total bit lengths of + * the compressed block data, excluding the tree representations. + */ + + /* Build the bit length tree for the above two trees, and get the index + * in bl_order of the last bit length code to send. + */ + max_blindex = build_bl_tree(s); + + /* Determine the best encoding. Compute first the block length in bytes*/ + opt_lenb = (s->opt_len+3+7)>>3; + static_lenb = (s->static_len+3+7)>>3; + + Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ", + opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len, + s->last_lit)); + + if (static_lenb <= opt_lenb) opt_lenb = static_lenb; + + } else { + Assert(buf != (char*)0, "lost buf"); + opt_lenb = static_lenb = stored_len + 5; /* force a stored block */ + } + + /* If compression failed and this is the first and last block, + * and if the .zip file can be seeked (to rewrite the local header), + * the whole file is transformed into a stored file: + */ +#ifdef STORED_FILE_OK +# ifdef FORCE_STORED_FILE + if (eof && s->compressed_len == 0L) { /* force stored file */ +# else + if (stored_len <= opt_lenb && eof && s->compressed_len==0L && seekable()) { +# endif + /* Since LIT_BUFSIZE <= 2*WSIZE, the input data must be there: */ + if (buf == (charf*)0) error ("block vanished"); + + copy_block(buf, (unsigned)stored_len, 0); /* without header */ + s->compressed_len = stored_len << 3; + s->method = STORED; + } else +#endif /* STORED_FILE_OK */ + +#ifdef FORCE_STORED + if (buf != (char*)0) { /* force stored block */ +#else + if (stored_len+4 <= opt_lenb && buf != (char*)0) { + /* 4: two words for the lengths */ +#endif + /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE. + * Otherwise we can't have processed more than WSIZE input bytes since + * the last block flush, because compression would have been + * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to + * transform a block into a stored block. + */ + _tr_stored_block(s, buf, stored_len, eof); + +#ifdef FORCE_STATIC + } else if (static_lenb >= 0) { /* force static trees */ +#else + } else if (static_lenb == opt_lenb) { +#endif + send_bits(s, (STATIC_TREES<<1)+eof, 3); + compress_block(s, (ct_data *)static_ltree, (ct_data *)static_dtree); + s->compressed_len += 3 + s->static_len; + } else { + send_bits(s, (DYN_TREES<<1)+eof, 3); + send_all_trees(s, s->l_desc.max_code+1, s->d_desc.max_code+1, + max_blindex+1); + compress_block(s, (ct_data *)s->dyn_ltree, (ct_data *)s->dyn_dtree); + s->compressed_len += 3 + s->opt_len; + } + Assert (s->compressed_len == s->bits_sent, "bad compressed size"); + init_block(s); + + if (eof) { + bi_windup(s); + s->compressed_len += 7; /* align on byte boundary */ + } + Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3, + s->compressed_len-7*eof)); + + return s->compressed_len >> 3; +} + +/* =========================================================================== + * Save the match info and tally the frequency counts. Return true if + * the current block must be flushed. + */ +int _tr_tally (s, dist, lc) + deflate_state *s; + unsigned dist; /* distance of matched string */ + unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */ +{ + s->d_buf[s->last_lit] = (ush)dist; + s->l_buf[s->last_lit++] = (uch)lc; + if (dist == 0) { + /* lc is the unmatched char */ + s->dyn_ltree[lc].Freq++; + } else { + s->matches++; + /* Here, lc is the match length - MIN_MATCH */ + dist--; /* dist = match distance - 1 */ + Assert((ush)dist < (ush)MAX_DIST(s) && + (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) && + (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match"); + + s->dyn_ltree[length_code[lc]+LITERALS+1].Freq++; + s->dyn_dtree[d_code(dist)].Freq++; + } + + /* Try to guess if it is profitable to stop the current block here */ + if (s->level > 2 && (s->last_lit & 0xfff) == 0) { + /* Compute an upper bound for the compressed length */ + ulg out_length = (ulg)s->last_lit*8L; + ulg in_length = (ulg)((long)s->strstart - s->block_start); + int dcode; + for (dcode = 0; dcode < D_CODES; dcode++) { + out_length += (ulg)s->dyn_dtree[dcode].Freq * + (5L+extra_dbits[dcode]); + } + out_length >>= 3; + Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ", + s->last_lit, in_length, out_length, + 100L - out_length*100L/in_length)); + if (s->matches < s->last_lit/2 && out_length < in_length/2) return 1; + } + return (s->last_lit == s->lit_bufsize-1); + /* We avoid equality with lit_bufsize because of wraparound at 64K + * on 16 bit machines and because stored blocks are restricted to + * 64K-1 bytes. + */ +} + +/* =========================================================================== + * Send the block data compressed using the given Huffman trees + */ +local void compress_block(s, ltree, dtree) + deflate_state *s; + ct_data *ltree; /* literal tree */ + ct_data *dtree; /* distance tree */ +{ + unsigned dist; /* distance of matched string */ + int lc; /* match length or unmatched char (if dist == 0) */ + unsigned lx = 0; /* running index in l_buf */ + unsigned code; /* the code to send */ + int extra; /* number of extra bits to send */ + + if (s->last_lit != 0) do { + dist = s->d_buf[lx]; + lc = s->l_buf[lx++]; + if (dist == 0) { + send_code(s, lc, ltree); /* send a literal byte */ + Tracecv(isgraph(lc), (stderr," '%c' ", lc)); + } else { + /* Here, lc is the match length - MIN_MATCH */ + code = length_code[lc]; + send_code(s, code+LITERALS+1, ltree); /* send the length code */ + extra = extra_lbits[code]; + if (extra != 0) { + lc -= base_length[code]; + send_bits(s, lc, extra); /* send the extra length bits */ + } + dist--; /* dist is now the match distance - 1 */ + code = d_code(dist); + Assert (code < D_CODES, "bad d_code"); + + send_code(s, code, dtree); /* send the distance code */ + extra = extra_dbits[code]; + if (extra != 0) { + dist -= base_dist[code]; + send_bits(s, dist, extra); /* send the extra distance bits */ + } + } /* literal or match pair ? */ + + /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */ + Assert((uInt)s->pending < s->lit_bufsize + 2*lx, "pendingBuf overflow"); + + } while (lx < s->last_lit); + + send_code(s, END_BLOCK, ltree); + s->last_eob_len = ltree[END_BLOCK].Len; +} + +/* =========================================================================== + * Set the data type to ASCII or BINARY, using a crude approximation: + * binary if more than 20% of the bytes are <= 6 or >= 128, ascii otherwise. + * IN assertion: the fields freq of dyn_ltree are set and the total of all + * frequencies does not exceed 64K (to fit in an int on 16 bit machines). + */ +local void set_data_type(s) + deflate_state *s; +{ + int n = 0; + unsigned ascii_freq = 0; + unsigned bin_freq = 0; + while (n < 7) bin_freq += s->dyn_ltree[n++].Freq; + while (n < 128) ascii_freq += s->dyn_ltree[n++].Freq; + while (n < LITERALS) bin_freq += s->dyn_ltree[n++].Freq; + s->data_type = (Byte)(bin_freq > (ascii_freq >> 2) ? Z_BINARY : Z_ASCII); +} + +/* =========================================================================== + * Reverse the first len bits of a code, using straightforward code (a faster + * method would use a table) + * IN assertion: 1 <= len <= 15 + */ +local unsigned bi_reverse(code, len) + unsigned code; /* the value to invert */ + int len; /* its bit length */ +{ + register unsigned res = 0; + do { + res |= code & 1; + code >>= 1, res <<= 1; + } while (--len > 0); + return res >> 1; +} + +/* =========================================================================== + * Flush the bit buffer, keeping at most 7 bits in it. + */ +local void bi_flush(s) + deflate_state *s; +{ + if (s->bi_valid == 16) { + put_short(s, s->bi_buf); + s->bi_buf = 0; + s->bi_valid = 0; + } else if (s->bi_valid >= 8) { + put_byte(s, (Byte)s->bi_buf); + s->bi_buf >>= 8; + s->bi_valid -= 8; + } +} + +/* =========================================================================== + * Flush the bit buffer and align the output on a byte boundary + */ +local void bi_windup(s) + deflate_state *s; +{ + if (s->bi_valid > 8) { + put_short(s, s->bi_buf); + } else if (s->bi_valid > 0) { + put_byte(s, (Byte)s->bi_buf); + } + s->bi_buf = 0; + s->bi_valid = 0; +#ifdef DEBUG + s->bits_sent = (s->bits_sent+7) & ~7; +#endif +} + +/* =========================================================================== + * Copy a stored block, storing first the length and its + * one's complement if requested. + */ +local void copy_block(s, buf, len, header) + deflate_state *s; + charf *buf; /* the input data */ + unsigned len; /* its length */ + int header; /* true if block header must be written */ +{ + bi_windup(s); /* align on byte boundary */ + s->last_eob_len = 8; /* enough lookahead for inflate */ + + if (header) { + put_short(s, (ush)len); + put_short(s, (ush)~len); +#ifdef DEBUG + s->bits_sent += 2*16; +#endif + } +#ifdef DEBUG + s->bits_sent += (ulg)len<<3; +#endif + while (len--) { + put_byte(s, *buf++); + } +} diff --git a/security/nss/cmd/zlib/trees.h b/security/nss/cmd/zlib/trees.h new file mode 100644 index 000000000..72facf900 --- /dev/null +++ b/security/nss/cmd/zlib/trees.h @@ -0,0 +1,128 @@ +/* header created automatically with -DGEN_TREES_H */ + +local const ct_data static_ltree[L_CODES+2] = { +{{ 12},{ 8}}, {{140},{ 8}}, {{ 76},{ 8}}, {{204},{ 8}}, {{ 44},{ 8}}, +{{172},{ 8}}, {{108},{ 8}}, {{236},{ 8}}, {{ 28},{ 8}}, {{156},{ 8}}, +{{ 92},{ 8}}, {{220},{ 8}}, {{ 60},{ 8}}, {{188},{ 8}}, {{124},{ 8}}, +{{252},{ 8}}, {{ 2},{ 8}}, {{130},{ 8}}, {{ 66},{ 8}}, {{194},{ 8}}, +{{ 34},{ 8}}, {{162},{ 8}}, {{ 98},{ 8}}, {{226},{ 8}}, {{ 18},{ 8}}, +{{146},{ 8}}, {{ 82},{ 8}}, {{210},{ 8}}, {{ 50},{ 8}}, {{178},{ 8}}, +{{114},{ 8}}, {{242},{ 8}}, {{ 10},{ 8}}, {{138},{ 8}}, {{ 74},{ 8}}, +{{202},{ 8}}, {{ 42},{ 8}}, {{170},{ 8}}, {{106},{ 8}}, {{234},{ 8}}, +{{ 26},{ 8}}, {{154},{ 8}}, {{ 90},{ 8}}, {{218},{ 8}}, {{ 58},{ 8}}, +{{186},{ 8}}, {{122},{ 8}}, {{250},{ 8}}, {{ 6},{ 8}}, {{134},{ 8}}, +{{ 70},{ 8}}, {{198},{ 8}}, {{ 38},{ 8}}, {{166},{ 8}}, {{102},{ 8}}, +{{230},{ 8}}, {{ 22},{ 8}}, {{150},{ 8}}, {{ 86},{ 8}}, {{214},{ 8}}, +{{ 54},{ 8}}, {{182},{ 8}}, {{118},{ 8}}, {{246},{ 8}}, {{ 14},{ 8}}, +{{142},{ 8}}, {{ 78},{ 8}}, {{206},{ 8}}, {{ 46},{ 8}}, {{174},{ 8}}, +{{110},{ 8}}, {{238},{ 8}}, {{ 30},{ 8}}, {{158},{ 8}}, {{ 94},{ 8}}, +{{222},{ 8}}, {{ 62},{ 8}}, {{190},{ 8}}, {{126},{ 8}}, {{254},{ 8}}, +{{ 1},{ 8}}, {{129},{ 8}}, {{ 65},{ 8}}, {{193},{ 8}}, {{ 33},{ 8}}, +{{161},{ 8}}, {{ 97},{ 8}}, {{225},{ 8}}, {{ 17},{ 8}}, {{145},{ 8}}, +{{ 81},{ 8}}, {{209},{ 8}}, {{ 49},{ 8}}, {{177},{ 8}}, {{113},{ 8}}, +{{241},{ 8}}, {{ 9},{ 8}}, {{137},{ 8}}, {{ 73},{ 8}}, {{201},{ 8}}, +{{ 41},{ 8}}, {{169},{ 8}}, {{105},{ 8}}, {{233},{ 8}}, {{ 25},{ 8}}, +{{153},{ 8}}, {{ 89},{ 8}}, {{217},{ 8}}, {{ 57},{ 8}}, {{185},{ 8}}, +{{121},{ 8}}, {{249},{ 8}}, {{ 5},{ 8}}, {{133},{ 8}}, {{ 69},{ 8}}, +{{197},{ 8}}, {{ 37},{ 8}}, {{165},{ 8}}, {{101},{ 8}}, {{229},{ 8}}, +{{ 21},{ 8}}, {{149},{ 8}}, {{ 85},{ 8}}, {{213},{ 8}}, {{ 53},{ 8}}, +{{181},{ 8}}, {{117},{ 8}}, {{245},{ 8}}, {{ 13},{ 8}}, {{141},{ 8}}, +{{ 77},{ 8}}, {{205},{ 8}}, {{ 45},{ 8}}, {{173},{ 8}}, {{109},{ 8}}, +{{237},{ 8}}, {{ 29},{ 8}}, {{157},{ 8}}, {{ 93},{ 8}}, {{221},{ 8}}, +{{ 61},{ 8}}, {{189},{ 8}}, {{125},{ 8}}, {{253},{ 8}}, {{ 19},{ 9}}, +{{275},{ 9}}, {{147},{ 9}}, {{403},{ 9}}, {{ 83},{ 9}}, {{339},{ 9}}, +{{211},{ 9}}, {{467},{ 9}}, {{ 51},{ 9}}, {{307},{ 9}}, {{179},{ 9}}, +{{435},{ 9}}, {{115},{ 9}}, {{371},{ 9}}, {{243},{ 9}}, {{499},{ 9}}, +{{ 11},{ 9}}, {{267},{ 9}}, {{139},{ 9}}, {{395},{ 9}}, {{ 75},{ 9}}, +{{331},{ 9}}, {{203},{ 9}}, {{459},{ 9}}, {{ 43},{ 9}}, {{299},{ 9}}, +{{171},{ 9}}, {{427},{ 9}}, {{107},{ 9}}, {{363},{ 9}}, {{235},{ 9}}, +{{491},{ 9}}, {{ 27},{ 9}}, {{283},{ 9}}, {{155},{ 9}}, {{411},{ 9}}, +{{ 91},{ 9}}, {{347},{ 9}}, {{219},{ 9}}, {{475},{ 9}}, {{ 59},{ 9}}, +{{315},{ 9}}, {{187},{ 9}}, {{443},{ 9}}, {{123},{ 9}}, {{379},{ 9}}, +{{251},{ 9}}, {{507},{ 9}}, {{ 7},{ 9}}, {{263},{ 9}}, {{135},{ 9}}, +{{391},{ 9}}, {{ 71},{ 9}}, {{327},{ 9}}, {{199},{ 9}}, {{455},{ 9}}, +{{ 39},{ 9}}, {{295},{ 9}}, {{167},{ 9}}, {{423},{ 9}}, {{103},{ 9}}, +{{359},{ 9}}, {{231},{ 9}}, {{487},{ 9}}, {{ 23},{ 9}}, {{279},{ 9}}, +{{151},{ 9}}, {{407},{ 9}}, {{ 87},{ 9}}, {{343},{ 9}}, {{215},{ 9}}, +{{471},{ 9}}, {{ 55},{ 9}}, {{311},{ 9}}, {{183},{ 9}}, {{439},{ 9}}, +{{119},{ 9}}, {{375},{ 9}}, {{247},{ 9}}, {{503},{ 9}}, {{ 15},{ 9}}, +{{271},{ 9}}, {{143},{ 9}}, {{399},{ 9}}, {{ 79},{ 9}}, {{335},{ 9}}, +{{207},{ 9}}, {{463},{ 9}}, {{ 47},{ 9}}, {{303},{ 9}}, {{175},{ 9}}, +{{431},{ 9}}, {{111},{ 9}}, {{367},{ 9}}, {{239},{ 9}}, {{495},{ 9}}, +{{ 31},{ 9}}, {{287},{ 9}}, {{159},{ 9}}, {{415},{ 9}}, {{ 95},{ 9}}, +{{351},{ 9}}, {{223},{ 9}}, {{479},{ 9}}, {{ 63},{ 9}}, {{319},{ 9}}, +{{191},{ 9}}, {{447},{ 9}}, {{127},{ 9}}, {{383},{ 9}}, {{255},{ 9}}, +{{511},{ 9}}, {{ 0},{ 7}}, {{ 64},{ 7}}, {{ 32},{ 7}}, {{ 96},{ 7}}, +{{ 16},{ 7}}, {{ 80},{ 7}}, {{ 48},{ 7}}, {{112},{ 7}}, {{ 8},{ 7}}, +{{ 72},{ 7}}, {{ 40},{ 7}}, {{104},{ 7}}, {{ 24},{ 7}}, {{ 88},{ 7}}, +{{ 56},{ 7}}, {{120},{ 7}}, {{ 4},{ 7}}, {{ 68},{ 7}}, {{ 36},{ 7}}, +{{100},{ 7}}, {{ 20},{ 7}}, {{ 84},{ 7}}, {{ 52},{ 7}}, {{116},{ 7}}, +{{ 3},{ 8}}, {{131},{ 8}}, {{ 67},{ 8}}, {{195},{ 8}}, {{ 35},{ 8}}, +{{163},{ 8}}, {{ 99},{ 8}}, {{227},{ 8}} +}; + +local const ct_data static_dtree[D_CODES] = { +{{ 0},{ 5}}, {{16},{ 5}}, {{ 8},{ 5}}, {{24},{ 5}}, {{ 4},{ 5}}, +{{20},{ 5}}, {{12},{ 5}}, {{28},{ 5}}, {{ 2},{ 5}}, {{18},{ 5}}, +{{10},{ 5}}, {{26},{ 5}}, {{ 6},{ 5}}, {{22},{ 5}}, {{14},{ 5}}, +{{30},{ 5}}, {{ 1},{ 5}}, {{17},{ 5}}, {{ 9},{ 5}}, {{25},{ 5}}, +{{ 5},{ 5}}, {{21},{ 5}}, {{13},{ 5}}, {{29},{ 5}}, {{ 3},{ 5}}, +{{19},{ 5}}, {{11},{ 5}}, {{27},{ 5}}, {{ 7},{ 5}}, {{23},{ 5}} +}; + +const uch _dist_code[DIST_CODE_LEN] = { + 0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, + 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, +10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, +12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, +13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, +14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, +15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 0, 0, 16, 17, +18, 18, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 22, 22, 22, 22, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, +29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29 +}; + +const uch _length_code[MAX_MATCH-MIN_MATCH+1]= { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 12, 12, +13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, +17, 17, 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, +19, 19, 19, 19, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, +21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 22, 22, 22, 22, +22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23, 23, +23, 23, 23, 23, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, +25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, +26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, +27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28 +}; + +local const int base_length[LENGTH_CODES] = { +0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 12, 14, 16, 20, 24, 28, 32, 40, 48, 56, +64, 80, 96, 112, 128, 160, 192, 224, 0 +}; + +local const int base_dist[D_CODES] = { + 0, 1, 2, 3, 4, 6, 8, 12, 16, 24, + 32, 48, 64, 96, 128, 192, 256, 384, 512, 768, + 1024, 1536, 2048, 3072, 4096, 6144, 8192, 12288, 16384, 24576 +}; + diff --git a/security/nss/cmd/zlib/uncompr.c b/security/nss/cmd/zlib/uncompr.c new file mode 100644 index 000000000..5e5a83247 --- /dev/null +++ b/security/nss/cmd/zlib/uncompr.c @@ -0,0 +1,58 @@ +/* uncompr.c -- decompress a memory buffer + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ +/* This file was modified since it was taken from the zlib distribution */ +/* $Id$ */ + +#include "zlib.h" + +/* =========================================================================== + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ +PR_PUBLIC_API(int) uncompress (dest, destLen, source, sourceLen) + Bytef *dest; + uLongf *destLen; + const Bytef *source; + uLong sourceLen; +{ + z_stream stream; + int err; + + stream.next_in = (Bytef*)source; + stream.avail_in = (uInt)sourceLen; + /* Check for source > 64K on 16-bit machine: */ + if ((uLong)stream.avail_in != sourceLen) return Z_BUF_ERROR; + + stream.next_out = dest; + stream.avail_out = (uInt)*destLen; + if ((uLong)stream.avail_out != *destLen) return Z_BUF_ERROR; + + stream.zalloc = (alloc_func)0; + stream.zfree = (free_func)0; + + err = inflateInit(&stream); + if (err != Z_OK) return err; + + err = inflate(&stream, Z_FINISH); + if (err != Z_STREAM_END) { + inflateEnd(&stream); + return err; + } + *destLen = stream.total_out; + + err = inflateEnd(&stream); + return err; +} diff --git a/security/nss/cmd/zlib/zconf.h b/security/nss/cmd/zlib/zconf.h new file mode 100644 index 000000000..096a448b4 --- /dev/null +++ b/security/nss/cmd/zlib/zconf.h @@ -0,0 +1,190 @@ +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ +/* This file was modified since it was taken from the zlib distribution */ +/* $Id$ */ + +#ifndef _ZCONF_H +#define _ZCONF_H + +/* + * If you *really* need a unique prefix for all types and library functions, + * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it. + */ +#ifdef Z_PREFIX +# define deflateInit_ z_deflateInit_ +# define deflate z_deflate +# define deflateEnd z_deflateEnd +# define inflateInit_ z_inflateInit_ +# define inflate z_inflate +# define inflateEnd z_inflateEnd +# define deflateInit2_ z_deflateInit2_ +# define deflateSetDictionary z_deflateSetDictionary +# define deflateCopy z_deflateCopy +# define deflateReset z_deflateReset +# define deflateParams z_deflateParams +# define inflateInit2_ z_inflateInit2_ +# define inflateSetDictionary z_inflateSetDictionary +# define inflateSync z_inflateSync +# define inflateReset z_inflateReset +# define compress z_compress +# define uncompress z_uncompress +# define adler32 z_adler32 +# define crc32 z_crc32 +# define get_crc_table z_get_crc_table + +# define Byte z_Byte +# define uInt z_uInt +# define uLong z_uLong +# define Bytef z_Bytef +# define charf z_charf +# define intf z_intf +# define uIntf z_uIntf +# define uLongf z_uLongf +# define voidpf z_voidpf +# define voidp z_voidp +#endif + +#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) +# define WIN32 +#endif +#if defined(__GNUC__) || defined(WIN32) || defined(__386__) || defined(i386) +# ifndef __32BIT__ +# define __32BIT__ +# endif +#endif +#if defined(__MSDOS__) && !defined(MSDOS) +# define MSDOS +#endif + +/* + * Compile with -DMAXSEG_64K if the alloc function cannot allocate more + * than 64k bytes at a time (needed on systems with 16-bit int). + */ +#if defined(MSDOS) && !defined(__32BIT__) +# define MAXSEG_64K +#endif +#ifdef MSDOS +# define UNALIGNED_OK +#endif + +#if (defined(MSDOS) || defined(_WINDOWS) || defined(WIN32) || defined(XP_OS2)) && !defined(STDC) +# define STDC +#endif +#if (defined(__STDC__) || defined(__cplusplus)) && !defined(STDC) +# define STDC +#endif + +#ifndef STDC +# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */ +# define const +# endif +#endif + +/* Some Mac compilers merge all .h files incorrectly: */ +#if defined(__MWERKS__) || defined(applec) ||defined(THINK_C) ||defined(__SC__) +# define NO_DUMMY_DECL +#endif + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2 */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + 1 << (windowBits+2) + 1 << (memLevel+9) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +# ifdef STDC +# define OF(args) args +# else +# define OF(args) () +# endif +#endif + +/* The following definitions for FAR are needed only for MSDOS mixed + * model programming (small or medium model with some far allocations). + * This was tested only with MSC; for other MSDOS compilers you may have + * to define NO_MEMCPY in zutil.h. If you don't need the mixed model, + * just define FAR to be empty. + */ +#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(__32BIT__) + /* MSC small or medium model */ +# define SMALL_MEDIUM +# ifdef _MSC_VER +# define FAR __far +# else +# define FAR far +# endif +#endif +#if defined(__BORLANDC__) && (defined(__SMALL__) || defined(__MEDIUM__)) +# ifndef __32BIT__ +# define SMALL_MEDIUM +# define FAR __far +# endif +#endif +#ifndef FAR +# define FAR +#endif + +typedef unsigned char Byte; /* 8 bits */ +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ + +#if defined(__BORLANDC__) && defined(SMALL_MEDIUM) + /* Borland C/C++ ignores FAR inside typedef */ +# define Bytef Byte FAR +#else + typedef Byte FAR Bytef; +#endif +typedef char FAR charf; +typedef int FAR intf; +typedef uInt FAR uIntf; +typedef uLong FAR uLongf; + +#ifdef STDC + typedef void FAR *voidpf; + typedef void *voidp; +#else + typedef Byte FAR *voidpf; + typedef Byte *voidp; +#endif + +#ifdef MOZILLA_CLIENT +#include "prtypes.h" +#else +/* Compile with -DZLIB_DLL for Windows DLL support */ +#if (defined(_WINDOWS) || defined(WINDOWS)) && defined(ZLIB_DLL) +# include <windows.h> +# define EXPORT WINAPI +#else +# define EXPORT +#endif + +/* #define PR_PUBLIC_API(type) type */ + +#endif /* MOZILLA_CLIENT */ + +#endif /* _ZCONF_H */ diff --git a/security/nss/cmd/zlib/zip16.def b/security/nss/cmd/zlib/zip16.def new file mode 100644 index 000000000..664eeab09 --- /dev/null +++ b/security/nss/cmd/zlib/zip16.def @@ -0,0 +1,24 @@ +LIBRARY zip1640.DLL +EXETYPE WINDOWS +PROTMODE + +DESCRIPTION '16-bit Zip DLL' + +STUB 'WINSTUB.EXE' + +CODE LOADONCALL MOVEABLE DISCARDABLE +DATA PRELOAD MOVEABLE SINGLE + +HEAPSIZE 8192 + +EXPORTS + +IMPORTS + _malloc = nspr3.2 + _realloc = nspr3.3 + _calloc = nspr3.4 + _free = nspr3.5 + _getenv = nspr3.9 + _printf = nspr3.11 + _sscanf = nspr3.33 + diff --git a/security/nss/cmd/zlib/zlib.h b/security/nss/cmd/zlib/zlib.h new file mode 100644 index 000000000..b216f00a3 --- /dev/null +++ b/security/nss/cmd/zlib/zlib.h @@ -0,0 +1,892 @@ +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.0.4, Jul 24th, 1996. + + Copyright (C) 1995-1996 Jean-loup Gailly and Mark Adler + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Jean-loup Gailly Mark Adler + gzip@prep.ai.mit.edu madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ +/* This file was modified since it was taken from the zlib distribution */ + +#ifndef _ZLIB_H +#define _ZLIB_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "zconf.h" + +#define ZLIB_VERSION "1.0.4" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms may be added later and will have the same + stream interface. + + For compression the application must provide the output buffer and + may optionally provide the input buffer for optimization. For decompression, + the application must provide the input buffer and may optionally provide + the output buffer for optimization. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The library does not install any signal handler. It is recommended to + add at least a handler for SIGSEGV when decompressing; the library checks + the consistency of the input data whenever possible but may go nuts + for some forms of corrupted input. +*/ + +typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size)); +typedef void (*free_func) OF((voidpf opaque, voidpf address)); + +struct internal_state; + +typedef struct z_stream_s { + Bytef *next_in; /* next input byte */ + uInt avail_in; /* number of bytes available at next_in */ + uLong total_in; /* total nb of input bytes read so far */ + + Bytef *next_out; /* next output byte should be put there */ + uInt avail_out; /* remaining free space at next_out */ + uLong total_out; /* total nb of bytes output so far */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state FAR *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + voidpf opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + uLong adler; /* adler32 value of the uncompressed data */ + uLong reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream FAR *z_streamp; + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +/* Allowed flush values; see deflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern const char *) zlibVersion (void); +#else +extern const char * EXPORT zlibVersion OF((void)); +#endif +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +extern int EXPORT deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) deflate (z_streamp strm, int flush); +#else +extern int EXPORT deflate OF((z_streamp strm, int flush)); +#endif +/* + Performs one or both of the following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_PARTIAL_FLUSH, the current compression + block is terminated and flushed to the output buffer so that the + decompressor can get all input data available so far. For method 9, a future + variant on method 8, the current block will be flushed but not terminated. + Z_SYNC_FLUSH has the same effect as partial flush except that the compressed + output is byte aligned (the compressor can clear its internal bit buffer) + and the current block is always terminated; this can be useful if the + compressor has to be restarted from scratch after an interruption (in which + case the internal state of the compressor may be lost). + If flush is set to Z_FULL_FLUSH, the compression block is terminated, a + special marker is output and the compression dictionary is discarded; this + is useful to allow the decompressor to synchronize if one compressed block + has been damaged (see inflateSync below). Flushing degrades compression and + so should be used only when necessary. Using Z_FULL_FLUSH too often can + seriously degrade the compression. If deflate returns with avail_out == 0, + this function must be called again with the same value of the flush + parameter and more output space (updated avail_out), until the flush is + complete (deflate returns with non-zero avail_out). + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + 0.1% larger than avail_in plus 12 bytes. If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible. +*/ + + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) deflateEnd (z_streamp strm); +#else +extern int EXPORT deflateEnd OF((z_streamp strm)); +#endif +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +extern int EXPORT inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + zalloc, zfree and opaque must be initialized before by the caller. If + zalloc and zfree are set to Z_NULL, inflateInit updates them to use default + allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_VERSION_ERROR if the zlib library version is incompatible + with the version assumed by the caller. msg is set to null if there is no + error message. inflateInit does not perform any decompression: this will be + done by inflate(). +*/ + + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) inflate (z_streamp strm, int flush); +#else +extern int EXPORT inflate OF((z_streamp strm, int flush)); +#endif +/* + Performs one or both of the following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + If the parameter flush is set to Z_PARTIAL_FLUSH, inflate flushes as much + output as possible to the output buffer. The flushing behavior of inflate is + not specified for values of the flush parameter other than Z_PARTIAL_FLUSH + and Z_FINISH, but the current implementation actually flushes as much output + as possible anyway. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + inflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if the end of the + compressed data has been reached and all uncompressed output has been + produced, Z_NEED_DICT if a preset dictionary is needed at this point (see + inflateSetDictionary below), Z_DATA_ERROR if the input data was corrupted, + Z_STREAM_ERROR if the stream structure was inconsistent (for example if + next_in or next_out was NULL), Z_MEM_ERROR if there was not enough memory, + Z_BUF_ERROR if no progress is possible or if there was not enough room in + the output buffer when Z_FINISH is used. In the Z_DATA_ERROR case, the + application may then call inflateSync to look for a good compression block. + In the Z_NEED_DICT case, strm->adler is set to the Adler32 value of the + dictionary chosen by the compressor. +*/ + + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) inflateEnd (z_streamp strm); +#else +extern int EXPORT inflateEnd OF((z_streamp strm)); +#endif +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +extern int EXPORT deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. (Method 9 will allow a 64K history buffer and + partial block flushes.) + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library (the value 16 will be allowed for method 9). Larger + values of this parameter result in better compression at the expense of + memory usage. The default value is 15 if deflateInit is used instead. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match). Filtered data consists mostly of small values with a + somewhat random distribution. In this case, the compression algorithm is + tuned to compress them better. The effect of Z_FILTERED is to force more + Huffman coding and less string matching; it is somewhat intermediate + between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects + the compression ratio but not the correctness of the compressed output even + if it is not set appropriately. + + If next_in is not null, the library will use this buffer to hold also + some history information; the buffer must either hold the entire input + data, or have at least 1<<(windowBits+1) bytes and be writable. If next_in + is null, the library will allocate its own history buffer (and leave next_in + null). next_out need not be provided here but must be provided by the + application for the next call of deflate(). + + If the history buffer is provided by the application, next_in must + must never be changed by the application since the compressor maintains + information inside this buffer from call to call; the application + must provide more input only by increasing avail_in. next_in is always + reset by the library in this case. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was + not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as + an invalid method). msg is set to null if there is no error message. + deflateInit2 does not perform any compression: this will be done by + deflate(). +*/ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) deflateSetDictionary (z_streamp strm, + const Bytef *dictionary, + uInt dictLength); +#else +extern int EXPORT deflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +#endif +/* + Initializes the compression dictionary (history buffer) from the given + byte sequence without producing any compressed output. This function must + be called immediately after deflateInit or deflateInit2, before any call + of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and + can be predicted with good accuracy; the data can then be compressed better + than with the default empty dictionary. In this version of the library, + only the last 32K bytes of the dictionary are used. + Upon return of this function, strm->adler is set to the Adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state + is inconsistent (for example if deflate has already been called for this + stream). deflateSetDictionary does not perform any compression: this will + be done by deflate(). +*/ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) deflateCopy (z_streamp dest, z_streamp source); +#else +extern int EXPORT deflateCopy OF((z_streamp dest, z_streamp source)); +#endif +/* + Sets the destination stream as a complete copy of the source stream. If + the source stream is using an application-supplied history buffer, a new + buffer is allocated for the destination stream. The compressed output + buffer is always application-supplied. It's the responsibility of the + application to provide the correct values of next_out and avail_out for the + next call of deflate. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) deflateReset (z_streamp strm); +#else +extern int EXPORT deflateReset OF((z_streamp strm)); +#endif +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) deflateParams (z_streamp strm, int level, int strategy); +#else +extern int EXPORT deflateParams OF((z_streamp strm, int level, int strategy)); +#endif +/* + Dynamically update the compression level and compression strategy. + This can be used to switch between compression and straight copy of + the input data, or to switch to a different kind of input data requiring + a different strategy. If the compression level is changed, the input + available so far is compressed with the old level (and may be flushed); + the new level will take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +/* +extern int EXPORT inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with more compression options. The + fields next_out, zalloc, zfree and opaque must be initialized before by + the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library (the value 16 will be allowed soon). The + default value is 15 if inflateInit is used instead. If a compressed stream + with a larger window size is given as input, inflate() will return with + the error code Z_DATA_ERROR instead of trying to allocate a larger window. + + If next_out is not null, the library will use this buffer for the history + buffer; the buffer must either be large enough to hold the entire output + data, or have at least 1<<windowBits bytes. If next_out is null, the + library will allocate its own buffer (and leave next_out null). next_in + need not be provided here but must be provided by the application for the + next call of inflate(). + + If the history buffer is provided by the application, next_out must + never be changed by the application since the decompressor maintains + history information inside this buffer from call to call; the application + can only reset next_out to the beginning of the history buffer when + avail_out is zero and all output has been consumed. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was + not enough memory, Z_STREAM_ERROR if a parameter is invalid (such as + windowBits < 8). msg is set to null if there is no error message. + inflateInit2 does not perform any decompression: this will be done by + inflate(). +*/ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) inflateSetDictionary (z_streamp strm, + const Bytef *dictionary, + uInt dictLength); +#else +extern int EXPORT inflateSetDictionary OF((z_streamp strm, + const Bytef *dictionary, + uInt dictLength)); +#endif +/* + Initializes the decompression dictionary (history buffer) from the given + uncompressed byte sequence. This function must be called immediately after + a call of inflate if this call returned Z_NEED_DICT. The dictionary chosen + by the compressor can be determined from the Adler32 value returned by this + call of inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) inflateSync (z_streamp strm); +#else +extern int EXPORT inflateSync OF((z_streamp strm)); +#endif +/* + Skips invalid compressed data until the special marker (see deflate() + above) can be found, or until all available input is skipped. No output + is provided. + + inflateSync returns Z_OK if the special marker has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no marker has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) inflateReset (z_streamp strm); +#else +extern int EXPORT inflateReset OF((z_streamp strm)); +#endif +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level, window size, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) compress (Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen); +#else +extern int EXPORT compress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +#endif +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) uncompress (Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen); +#else +extern int EXPORT uncompress OF((Bytef *dest, uLongf *destLen, + const Bytef *source, uLong sourceLen)); +#endif +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ + + +typedef voidp gzFile; + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern gzFile) gzopen (const char *path, const char *mode); +#else +extern gzFile EXPORT gzopen OF((const char *path, const char *mode)); +#endif +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9"). gzopen can be used to read a file which is not in gzip format; + in this case gzread will directly read from the file without decompression. + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). +*/ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern gzFile) gzdopen (int fd, const char *mode); +#else +extern gzFile EXPORT gzdopen OF((int fd, const char *mode)); +#endif +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) gzread (gzFile file, voidp buf, unsigned len); +#else +extern int EXPORT gzread OF((gzFile file, voidp buf, unsigned len)); +#endif +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) gzwrite (gzFile file, const voidp buf, unsigned len); +#else +extern int EXPORT gzwrite OF((gzFile file, const voidp buf, unsigned len)); +#endif +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) gzflush (gzFile file, int flush); +#else +extern int EXPORT gzflush OF((gzFile file, int flush)); +#endif +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) gzclose (gzFile file); +#else +extern int EXPORT gzclose OF((gzFile file)); +#endif +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern const char *) gzerror (gzFile file, int *errnum); +#else +extern const char * EXPORT gzerror OF((gzFile file, int *errnum)); +#endif +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern uLong) adler32 (uLong adler, const Bytef *buf, uInt len); +#else +extern uLong EXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len)); +#endif + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern uLong) crc32 (uLong crc, const Bytef *buf, uInt len); +#else +extern uLong EXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len)); +#endif +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +#ifdef MOZILLA_CLIENT +PR_PUBLIC_API(extern int) deflateInit_ (z_streamp strm, int level, const char *version, + int stream_size); +PR_PUBLIC_API(extern int) inflateInit_ (z_streamp strm, const char *version, + int stream_size); +PR_PUBLIC_API(extern int) deflateInit2_ (z_streamp strm, int level, int method, + int windowBits, int memLevel, int strategy, + const char *version, int stream_size); +PR_PUBLIC_API(extern int) inflateInit2_ (z_streamp strm, int windowBits, + const char *version, int stream_size); +#else +extern int EXPORT deflateInit_ OF((z_streamp strm, int level, const char *version, + int stream_size)); +extern int EXPORT inflateInit_ OF((z_streamp strm, const char *version, + int stream_size)); +extern int EXPORT deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, int strategy, + const char *version, int stream_size)); +extern int EXPORT inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +#endif /* MOZILLA_CLIENT */ + + +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + +#if !defined(_Z_UTIL_H) && !defined(NO_DUMMY_DECL) + struct internal_state {int dummy;}; /* hack for buggy compilers */ +#endif + +uLongf *get_crc_table OF((void)); /* can be used by asm versions of crc32() */ + +#ifdef __cplusplus +} +#endif + +#endif /* _ZLIB_H */ diff --git a/security/nss/cmd/zlib/zutil.c b/security/nss/cmd/zlib/zutil.c new file mode 100644 index 000000000..afca3ed0c --- /dev/null +++ b/security/nss/cmd/zlib/zutil.c @@ -0,0 +1,215 @@ +/* zutil.c -- target dependent utility functions for the compression library + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ +/* This file was modified since it was taken from the zlib distribution */ +/* $Id$ */ + +#include <stdio.h> + +#include "zutil.h" + +#ifdef MOZILLA_CLIENT +#include "prtypes.h" +#include "prlog.h" +#endif + +struct internal_state {int dummy;}; /* for buggy compilers */ + +#ifndef STDC +extern void exit OF((int)); +#endif + +const char *z_errmsg[10] = { +"need dictionary", /* Z_NEED_DICT 2 */ +"stream end", /* Z_STREAM_END 1 */ +"", /* Z_OK 0 */ +"file error", /* Z_ERRNO (-1) */ +"stream error", /* Z_STREAM_ERROR (-2) */ +"data error", /* Z_DATA_ERROR (-3) */ +"insufficient memory", /* Z_MEM_ERROR (-4) */ +"buffer error", /* Z_BUF_ERROR (-5) */ +"incompatible version",/* Z_VERSION_ERROR (-6) */ +""}; + + +PR_PUBLIC_API(const char *) zlibVersion() +{ + return ZLIB_VERSION; +} + +#if defined(DEBUG) && defined(MOZILLA_CLIENT) +void z_error (m) + char *m; +{ + PR_ASSERT(0); +} +#endif + +#ifndef HAVE_MEMCPY + +void zmemcpy(dest, source, len) + Bytef* dest; + Bytef* source; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = *source++; /* ??? to be unrolled */ + } while (--len != 0); +} + +int zmemcmp(s1, s2, len) + Bytef* s1; + Bytef* s2; + uInt len; +{ + uInt j; + + for (j = 0; j < len; j++) { + if (s1[j] != s2[j]) return 2*(s1[j] > s2[j])-1; + } + return 0; +} + +void zmemzero(dest, len) + Bytef* dest; + uInt len; +{ + if (len == 0) return; + do { + *dest++ = 0; /* ??? to be unrolled */ + } while (--len != 0); +} +#endif + +#ifdef __TURBOC__ +#if (defined( __BORLANDC__) || !defined(SMALL_MEDIUM)) && !defined(__32BIT__) +/* Small and medium model in Turbo C are for now limited to near allocation + * with reduced MAX_WBITS and MAX_MEM_LEVEL + */ +# define MY_ZCALLOC + +/* Turbo C malloc() does not allow dynamic allocation of 64K bytes + * and farmalloc(64K) returns a pointer with an offset of 8, so we + * must fix the pointer. Warning: the pointer must be put back to its + * original form in order to free it, use zcfree(). + */ + +#define MAX_PTR 10 +/* 10*64K = 640K */ + +local int next_ptr = 0; + +typedef struct ptr_table_s { + voidpf org_ptr; + voidpf new_ptr; +} ptr_table; + +local ptr_table table[MAX_PTR]; +/* This table is used to remember the original form of pointers + * to large buffers (64K). Such pointers are normalized with a zero offset. + * Since MSDOS is not a preemptive multitasking OS, this table is not + * protected from concurrent access. This hack doesn't work anyway on + * a protected system like OS/2. Use Microsoft C instead. + */ + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + voidpf buf = opaque; /* just to make some compilers happy */ + ulg bsize = (ulg)items*size; + + /* If we allocate less than 65520 bytes, we assume that farmalloc + * will return a usable pointer which doesn't have to be normalized. + */ + if (bsize < 65520L) { + buf = farmalloc(bsize); + if (*(ush*)&buf != 0) return buf; + } else { + buf = farmalloc(bsize + 16L); + } + if (buf == NULL || next_ptr >= MAX_PTR) return NULL; + table[next_ptr].org_ptr = buf; + + /* Normalize the pointer to seg:0 */ + *((ush*)&buf+1) += ((ush)((uch*)buf-0) + 15) >> 4; + *(ush*)&buf = 0; + table[next_ptr++].new_ptr = buf; + return buf; +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + int n; + if (*(ush*)&ptr != 0) { /* object < 64K */ + farfree(ptr); + return; + } + /* Find the original pointer */ + for (n = 0; n < next_ptr; n++) { + if (ptr != table[n].new_ptr) continue; + + farfree(table[n].org_ptr); + while (++n < next_ptr) { + table[n-1] = table[n]; + } + next_ptr--; + return; + } + ptr = opaque; /* just to make some compilers happy */ + Assert(0, "zcfree: ptr not found"); +} +#endif +#endif /* __TURBOC__ */ + + +#if defined(M_I86) && !defined(__32BIT__) +/* Microsoft C in 16-bit mode */ + +# define MY_ZCALLOC + +#if (!defined(_MSC_VER) || (_MSC_VER < 600)) +# define _halloc halloc +# define _hfree hfree +#endif + +voidpf zcalloc (voidpf opaque, unsigned items, unsigned size) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + return _halloc((long)items, size); +} + +void zcfree (voidpf opaque, voidpf ptr) +{ + if (opaque) opaque = 0; /* to make compiler happy */ + _hfree(ptr); +} + +#endif /* MSC */ + + +#ifndef MY_ZCALLOC /* Any system without a special alloc function */ + +#ifndef STDC +extern voidp calloc OF((uInt items, uInt size)); +extern void free OF((voidpf ptr)); +#endif + +voidpf zcalloc (opaque, items, size) + voidpf opaque; + unsigned items; + unsigned size; +{ + if (opaque) items += size - size; /* make compiler happy */ + return (voidpf)calloc(items, size); +} + +void zcfree (opaque, ptr) + voidpf opaque; + voidpf ptr; +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + +#endif /* MY_ZCALLOC */ diff --git a/security/nss/cmd/zlib/zutil.h b/security/nss/cmd/zlib/zutil.h new file mode 100644 index 000000000..6918260cf --- /dev/null +++ b/security/nss/cmd/zlib/zutil.h @@ -0,0 +1,211 @@ +/* zutil.h -- internal interface and configuration of the compression library + * Copyright (C) 1995-1996 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ +/* This file was modified since it was taken from the zlib distribution */ +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* $Id$ */ + +#ifndef _Z_UTIL_H +#define _Z_UTIL_H + +#include "zlib.h" + +#if defined(_WIN32_WCE) +#elif defined(MSDOS)||defined(VMS)||defined(CRAY)||defined(WIN32)||defined(RISCOS) +# include <stddef.h> +# include <errno.h> +#else + extern int errno; +#endif +#ifdef STDC +# include <string.h> +# include <stdlib.h> +#endif + +#ifndef local +# define local static +#endif +/* compile with -Dlocal if your debugger can't find static symbols */ + +typedef unsigned char uch; +typedef uch FAR uchf; +typedef unsigned short ush; +typedef ush FAR ushf; +typedef unsigned long ulg; + +extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + +#ifdef MSDOS +# define OS_CODE 0x00 +# ifdef __TURBOC__ +# include <alloc.h> +# else /* MSC or DJGPP */ +# include <malloc.h> +# endif +#endif + +#ifdef OS2 +# define OS_CODE 0x06 +#endif + +#ifdef WIN32 /* Window 95 & Windows NT */ +# define OS_CODE 0x0b +#endif + +#if defined(VAXC) || defined(VMS) +# define OS_CODE 0x02 +# define FOPEN(name, mode) \ + fopen((name), (mode), "mbc=60", "ctx=stm", "rfm=fix", "mrs=512") +#endif + +#ifdef AMIGA +# define OS_CODE 0x01 +#endif + +#if defined(ATARI) || defined(atarist) +# define OS_CODE 0x05 +#endif + +#ifdef MACOS +# define OS_CODE 0x07 +#endif + +#ifdef __50SERIES /* Prime/PRIMOS */ +# define OS_CODE 0x0F +#endif + +#ifdef TOPS20 +# define OS_CODE 0x0a +#endif + +#if defined(_BEOS_) || defined(RISCOS) +# define fdopen(fd,mode) NULL /* No fdopen() */ +#endif + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef FOPEN +# define FOPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#ifdef HAVE_STRERROR +#ifndef MOZILLA_CLIENT + extern char *strerror OF((int)); +#endif +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#if defined(pyr) +# define NO_MEMCPY +#endif +#if (defined(M_I86SM) || defined(M_I86MM)) && !defined(_MSC_VER) + /* Use our own functions for small and medium model with MSC <= 5.0. + * You may have to use the same strategy for Borland C (untested). + */ +# define NO_MEMCPY +#endif +#if defined(STDC) && !defined(HAVE_MEMCPY) && !defined(NO_MEMCPY) +# define HAVE_MEMCPY +#endif +#ifdef HAVE_MEMCPY +# ifdef SMALL_MEDIUM /* MSDOS small or medium model */ +# define zmemcpy _fmemcpy +# define zmemcmp _fmemcmp +# define zmemzero(dest, len) _fmemset(dest, 0, len) +# else +# define zmemcpy memcpy +# define zmemcmp memcmp +# define zmemzero(dest, len) memset(dest, 0, len) +# endif +#else + extern void zmemcpy OF((Bytef* dest, Bytef* source, uInt len)); + extern int zmemcmp OF((Bytef* s1, Bytef* s2, uInt len)); + extern void zmemzero OF((Bytef* dest, uInt len)); +#endif + +/* Diagnostic functions */ +#ifdef DEBUG_ZLIB +# include <stdio.h> +# ifndef verbose +# define verbose 0 +# endif + extern void z_error OF((char *m)); +# define Assert(cond,msg) {if(!(cond)) z_error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# include <stdio.h> +# ifndef verbose +# define verbose 0 +# endif + extern void z_error OF((char *m)); +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (*check_func) OF((uLong check, const Bytef *buf, uInt len)); + +voidpf zcalloc OF((voidpf opaque, unsigned items, unsigned size)); +void zcfree OF((voidpf opaque, voidpf ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidpf)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + +#endif /* _Z_UTIL_H */ |